JavaFX changing Locale in whole application - javafx

Here is my StartApp.java, entry point of my application.
public class StartApp extends Application {
private Locale locale = new Locale("en");
public Locale getLocale(){
return locale;
}
public void setLocale(Locale locale){
this.locale = locale;
}
#Override
public void start(Stage primaryStage) throws Exception{
ResourceBundle bundle = ResourceBundle.getBundle("resources.bundles/MyBundle", locale);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../view/LoginView.fxml"), bundle);
Parent root = fxmlLoader.load();
primaryStage.setTitle("Title");
primaryStage.setScene(new Scene(root, 750, 400));
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args) throws SQLException {
launch(args);
}
Then on LoginController.java I create instance of StartApp and set onActions for 2 buttons
StartApp startApp = new StartApp();
#Override
public void initialize(URL location, ResourceBundle resources) {
bundle = resources;
plBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
try {
startApp.setLocale(new Locale("pl"));
changeLanguage(event);
} catch (Exception e) {
e.printStackTrace();
}
}
});
enBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
try {
startApp.setLocale(new Locale("en"));
changeLanguage(event);
} catch (Exception e) {
e.printStackTrace();
}
}
});
here is my changeLanguage method, which refresh current window and changes its language
public void changeLanguage(ActionEvent event) throws Exception{
((Node)event.getSource()).getScene().getWindow().hide();
Stage primaryStage = new Stage();
ResourceBundle bundle = ResourceBundle.getBundle("resources.bundles/MyBundle", startApp.getLocale());
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../view/LoginView.fxml"), bundle);
Parent root = fxmlLoader.load();
primaryStage.setTitle("Title2");
primaryStage.setScene(new Scene(root, 750, 400));
primaryStage.setResizable(false);
primaryStage.show();
}
And till now everything works fine, it changes language once I click buttons. But what I want to do now is to open new window(stage) with choosen language, but unfortunatelly, it always open new scene with language set on StartApp.
Here is method in LoginController than opens new stage.
public void register(ActionEvent event) throws Exception{
((Node)event.getSource()).getScene().getWindow().hide();
Stage primaryStage = new Stage();
ResourceBundle bundle = ResourceBundle.getBundle("resources.bundles/MyBundle", startApp.getLocale());
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../view/RegisterView.fxml"), bundle);
Parent root = fxmlLoader.load();
primaryStage.setTitle("Title2");
primaryStage.setScene(new Scene(root, 750, 400));
primaryStage.setResizable(false);
primaryStage.show();
}
Btw. Iv tried just extending StartApp to LoginController, making locale public, etc, everytime it ends up the same. When I created
Locale newLocale = null;
in LoginController, and then tried to assign values to it once I click buttons defined in initialize, I got nullpointerexception.

I don't know how to change all text by one command.
To keep it simlpe i just rename each element separately.
Example:
i18n/messages.properties
label.welcome = Welcome
i18n/messages_ukr.properties
label.welcome = Ласкаво просимо
i18n/messages_rus.properties
label.welcome = Добро пожаловать
Singleton Context.java which will contain current locale:
public class Context {
private final List<Locale> availableLocales;
private Locale currentLocale;
private static Context instance;
public static Context getInstance() {
if (instance == null) {
instance = new Context();
}
return instance;
}
private Context() {
availableLocales = new LinkedList<>();
availableLocales.add(new Locale("eng"));
availableLocales.add(new Locale("ukr"));
availableLocales.add(new Locale("rus"));
currentLocale = new Locale("eng"); // default locale
}
/**
* This method is used to return available locales
*
* #return available locales
*/
public List<Locale> getAvailableLocales() {
return availableLocales;
}
/**
* This method is used to return current locale setting
*
* #return current locale
*/
public Locale getCurrentLocale() {
return currentLocale;
}
/**
* This method is used to set current locale setting
*
* #param currentLocale locale to set
*/
public void setCurrentLocale(Locale currentLocale) {
this.currentLocale = currentLocale;
}
Util class MessageUtil.java will return message in current locale (seted in Context):
/**
* This class is used to provide methods to work with localized messages
*
* #author manfredi
*/
public abstract class MessageUtil {
private final static Logger logger = LoggerFactory.getLogger(MessageUtil.class);
private final static String RESOURCE_NAME = "i18n.messages";
/**
* This method is used to return resource bundle with current locale
*
* #return resource bundle with current locale. Otherwise resource bundle with default locale.
*/
public static ResourceBundle getResourceBundle() {
return ResourceBundle.getBundle(RESOURCE_NAME, Context.getInstance().getCurrentLocale());
}
/**
* This method is used to return localized message by it`s {#code key}
*
* #param key message key
* #return localized message
*/
public static String getMessage(String key) {
String message;
try {
message = getResourceBundle().getString(key);
} catch (MissingResourceException e) {
logger.error("{}", e.getMessage());
message = key;
}
return message;
}
/**
* This method is used to format localized message by it`s {#code key} using {#code args} as arguments list
*
* #param key message key by which the corresponding message will be found
* #param args list of arguments used in the message
* #return formatted localized message
*/
public static String formatMessage(String key, Object... args) {
MessageFormat messageFormat = new MessageFormat(getMessage(key), getResourceBundle().getLocale());
return messageFormat.format(args);
}
}
I use SceneBuilder tool for creating *.fxml files.
For example screen controller for one of this files that contain Label and ChoiceBox for language change might looks like following:
public class LanguageChangeScreenController implements Initializable {
#FXML
private Label welcomeLabel;
#FXML
private ChoiceBox<Locale> languageChoiceBox;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
initLanguageChangeListener();
refreshLocalization(); // I use %key.name syntax in .fxml files to initialize component's names instead of calling this method here
}
**
* This method is used to update the name of each component on the screen
*/
private void refreshLocalization() {
welcomeLabel.setText(MessageUtil.getMessage("label.welcome"));
}
private void initLanguageChangeListener() {
languageChoiceBox.getItems().addAll(Context.getInstance().getAvailableLocales());
languageChoiceBox.getSelectionModel().select(Context.getInstance().getCurrentLocale());
languageChoiceBox.setOnAction(actionEvent -> {
Context.getInstance().setCurrentLocale(languageChoiceBox.getSelectionModel().getSelectedItem());
refreshLocalization();
});
}
}

Related

JavaFX static ObservableList not refreshing ComboBox

What I'm trying to do is have a single class that maintains a static ObservableList of countries. I want to display these countries in a ComboBox. I've got this part working fine. Now, I also want to enable the user to add new countries to the list. So, there is a button beside the combo box that will show another dialog allowing entry of another country name. After the user enters the country name and clicks save, I would like the single static ObservableList to be updated with the new country and then it show up in the ComboBox. This part is not happening.
I'll show what DOES work, and what does not.
Saving a reference to the static list and updating that works. Like so:
public class CustomerController implements Initializable {
private ObservableList<Country> countryList;
#Override
public void initialize(URL url, ResourceBundle rb) {
countryList = Country.getCountryList();
comboCountry.setItems(countryList);
}
...
// Fired when clicking the "new country" button
#FXML
void handleNewCountry(ActionEvent event) {
Country country = new Country();
country.setCountry("Austria");
countryList.add(country);
}
}
This is what I would like to do, however it does not work:
public class CustomerController implements Initializable {
#FXML
private ComboBox<Country> comboCountry;
#Override
public void initialize(URL url, ResourceBundle rb) {
comboCountry.setItems(Country.getCountryList());
}
#FXML
void handleNewCountry(ActionEvent event) {
showScene("Country.fxml", "dialog.newCountry");
}
private void showScene(String sceneResource, String titleResource) {
try {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(sceneResource),
resourceBundle
);
Scene scene = new Scene(loader.load());
getNewStage(resourceBundle.getString(titleResource), scene).showAndWait();
} catch (IOException e) {
e.printStackTrace();
}
}
private Stage getNewStage(String title, Scene scene) {
Stage stage = new Stage();
stage.setTitle(title);
stage.setResizable(false);
stage.setScene(scene);
stage.initOwner(rootPane.getScene().getWindow());
stage.initModality(Modality.APPLICATION_MODAL);
return stage;
}
}
The Country class:
public class Country extends BaseModel {
private int countryID;
private StringProperty country;
private static ObservableList<Country> countryList; // The static observable list
public Country() {
countryList = FXCollections.observableArrayList();
country = new SimpleStringProperty();
}
public int getCountryID() {
return countryID;
}
public void setCountryID(int countryID) {
this.countryID = countryID;
}
public StringProperty countryProperty() {
return this.country;
}
public String getCountry() {
return this.country.get();
}
public void setCountry(String country) {
this.country.set(country);
}
public boolean equals(Country country) {
if (this.getCountry().compareToIgnoreCase(country.getCountry()) != 0) {
return false;
}
return true;
}
public static ObservableList<Country> getCountryList() {
if (countryList.size() < 1) {
updateCountryList();
}
return countryList;
}
public static void updateCountryList() {
countryList.clear();
ArrayList<Country> daoList = CountryDao.listCountries();
for (Country country : daoList) {
countryList.add(country);
}
}
#Override
public String toString() {
return this.getCountry();
}
}
And the dialog for entering a new country:
public class CountryController implements Initializable {
#FXML
private TextField textCountry;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
void handleSave(ActionEvent event) {
Country country = new Country();
country.setCountry(textCountry.getText().trim());
CountryDao.insert(country); // Insert the country into the database
Country.updateCountryList(); // Update the static ObservableList
close();
}
#FXML
void handleCancel() {
close();
}
void close() {
final Stage stage = (Stage) textCountry.getScene().getWindow();
stage.close();
}
}
So, my theory is that somehow the ComboBox is creating a new instance of the ObservableList when setItems is called. I'm really not sure though. A static object should only have one instance, so updating it from anywhere should update that ComboBox. Anyone know what's up with this?
You're creating a new ObservableList instance every time the Country constructor is invoked. This way a list different to the one used with the ComboBox is modified.
If you really need to keep the list of countries in a static field (this is considered bad practice), you should make sure to only create a single ObservableList:
private static final ObservableList<Country> countryList = FXCollections.observableArrayList();
(Remove the assignment of this field from the constructor too.)

Binding JavaFX Label to StringProperty

In my JavaFX application I have a label that I want to update with the StringProperty of another class that defines server functionality.
In the server class I have a StringProperty defined as shown below:
public class eol_server {
private StringProperty serverMessagesProperty;
etc..
I have a method to return the StringProperty on request:
public StringProperty serverMessagesProperty() {
if (serverMessagesProperty == null) {
serverMessagesProperty = new SimpleStringProperty();
}
return serverMessagesProperty;
}
In the main gui class, Start() method I build the Scene, then instantiate a new server object. After this I update one of the labels in my Scene graph by binding it to the StringProperty of the server object:
public void start(Stage primaryStage) {
...set up all the gui components
primaryStage.show();
dss = new eol_server();
lbl_dssMessage.textProperty().bind(dss.getServerMessagesProperty());
}
When I run the application, the scene is rendered as I expect, and the lbl_dssMessage text is set to value that is set up in the constructor of eol_server. But, from that point on the binding is not working, although I have actions that would update the StringProperty of the dss object they are not updating the label in the GUI.
Here is the complete file that generates a stripped down version of the scene:
public class eol_gui extends Application {
private static eol_server dss = null;
private static Stage primaryStage;
/**
* Application Main Function
* #param args
*/
public static void main(String[] args) {
launch(args);
}
/**
* #param stage
*/
private void setPrimaryStage(Stage stage) {
eol_gui.primaryStage = stage;
}
/**
* #return Stage for GUI
*/
static public Stage getPrimaryStage() {
return eol_gui.primaryStage;
}
/* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
*/
#Override
public void start(Stage primaryStage) {
setPrimaryStage(primaryStage);
BorderPane root = new BorderPane();
Label lbl_dssMessage = new Label("initialized");
HBox topMenu = new HBox();
topMenu.getChildren().add(lbl_dssMessage);
eol_supervisor_I config1 = new eol_supervisor_I();
// Build Scene
root.setStyle("-fx-background-color: #FFFFFF;");
root.setTop(topMenu);
primaryStage.setScene(new Scene(root, 300, 50));
primaryStage.show();
dss = new eol_server();
dss.getServerMessagesProperty().addListener(new ChangeListener<Object>() {
#Override
public void changed(ObservableValue<?> o,Object oldVal,Object newVal)
{
//Option 1: lbl_dssMessage.setText(newVal.toString());
}
});
//Option 2
lbl_dssMessage.textProperty().bind(dss.serverMessagesProperty);
}
}
As you can see I have tried the bind method and a change listener. It looks like bind was working, as was the listener, in all cases except those that run in the server service threads. These throw the IllegalStateException due to not being on the main JavaFX application thread. How do I safely and correctly exchange messages from the service to the main thread?
The server is defined in the following class, which is intended to run services independent of the main JavaFX thread. But I would like to exchange info between the threads to show status. Ii'm trying to avoid the GUI hanging while the server connections and data exchanges are made.
public class eol_server {
public StringProperty serverMessagesProperty;
public eol_server() {
/* Create Scripting Environment */
serverMessagesProperty().set("Establishing Debug Server Environment");
connect();
}
public boolean connect() {
serverMessagesProperty().set("Creating Server");
ConnectService connectService = new ConnectService();
connectService.start();
return false;
}
public StringProperty serverMessagesProperty() {
if (serverMessagesProperty == null) {
serverMessagesProperty = new SimpleStringProperty();
}
return serverMessagesProperty;
}
public StringProperty getServerMessagesProperty() {
return serverMessagesProperty;
}
private class ConnectService extends Service<Void> {
#Override
protected void succeeded() {
}
#Override
protected void failed() {
}
#Override
protected void cancelled() {
}
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
serverMessagesProperty().set("Connecting....");
Thread.sleep(5000);
// DEMO: uncomment to provoke "Not on FX application thread"-Exception:
// connectButton.setVisible(false);
serverMessagesProperty().set("Waiting for server feedback");
Thread.sleep(5000);
return null;
}
};
}
}
private class DisconnectService extends Service<Void> {
#Override
protected void succeeded() {
}
#Override
protected void cancelled() {
}
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
updateMessage("Disconnecting....");
serverMessagesProperty().set("Disconnecting....");
Thread.sleep(5000);
updateMessage("Waiting for server feedback.");
serverMessagesProperty().set("Waiting for server feedback.");
Thread.sleep(5000);
return null;
}
};
}
}
}
Thanks in advance
JW
Read the below paragraph from JavaFX Node documentation.
Node objects may be constructed and modified on any thread as long
they are not yet attached to a Scene in a Window that is showing. An
application must attach nodes to such a Scene or modify them on the
JavaFX Application Thread.
The correct and more functional way to solve your problem is
dss.serverMessagesProperty.addListener((observable, oldValue, newValue) -> Platform.runLater(() -> lbl_dssMessage.setText(newValue));
I seem to have a solution, derived from what I read on the runlater() Platform method. Also see discussion here
Multi-Threading error when binding a StringProperty
changing my listener to invoke the message update via runLater seems to break the multi-threading problem. Yes I expect it is not immediate but it will be very very close to immediate and good enough. I appreciate that JavaFX requires you to not mess with the Application thread values / nodes etc etc of the scene graph but it is quite a complicated area of the JavaFX library.
Here is the listener that worked for me
// Get new DSS session active
dss = new eol_server();
dss.serverMessagesProperty.addListener(new ChangeListener<Object>() {
#Override
public void changed (ObservableValue<?> observable, Object oldValue, Object newValue) {
Platform.runLater(() -> lbl_dssMessage.setText(newValue.toString()));
}
});
}
Happy for further discussion as to why this works when the other options did not, also open to any other more elegant suggestions.

How to prepare FXML Controller to be GC

I have an issue in my application. Any Controllers are garbage collected.
I was prepared one, pretty simple with clear function, but it is no removed from memory.
#Log4j2
public class DialogOpenProjectController extends DialogPane implements Initializable, FXMLController, FXMLPane, FXMLDialogController {
#FXML
private ObjectProperty<ResourceBundle> languageBundle = new SimpleObjectProperty<>();
#FXML
private JFXTabPane TAB_PANE_OPEN_PROJECT;
#FXML
private JFXButton BUTTON_CONFIRM;
private Tab tabOpenNewProject;
private Tab tabOpenExistingProject;
private Stage stage;
private ChangeListener<? super ResourceBundle> languageListener = this::languageChange;
private ChangeListener<? super Tab> selectedTabListener = this::selectedTabChanged;
{
tabOpenExistingProject = new Tab();
tabOpenNewProject = new Tab();
}
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
log.trace(LogMessages.MSG_CTRL_INITIALIZATION);
this.languageBundle.setValue(rb);
initTabs();
addSelectedTabListener();
addDisableButtonListener();
addLanguageListener();
log.trace(LogMessages.MSG_CTRL_INITIALIZED);
}
#FXML
public void cancel() {
this.stage.close();
clean();
}
#FXML
public void confirm() {
if (TAB_PANE_OPEN_PROJECT.getSelectionModel().getSelectedItem().equals(tabOpenNewProject)) {
actionNewProject();
} else if (TAB_PANE_OPEN_PROJECT.getSelectionModel().getSelectedItem().equals(tabOpenExistingProject)) {
actionOpenProject();
} else {
//To to show error
}
this.stage.close();
clean();
}
private void initTabs() {
TAB_PANE_OPEN_PROJECT.getSelectionModel().select(tabOpenNewProject);
}
private void addSelectedTabListener() {
TAB_PANE_OPEN_PROJECT.getSelectionModel().selectedItemProperty().addListener(selectedTabListener);
}
private void addDisableButtonListener() {
//nothing to do temporary
}
private void clean() {
this.languageBundle.removeListener(languageListener);
languageBundle.unbind();
languageBundle.setValue(null);
TAB_PANE_OPEN_PROJECT.getSelectionModel().selectedItemProperty().removeListener(selectedTabListener);
TAB_PANE_OPEN_PROJECT.getSelectionModel().clearSelection();
TAB_PANE_OPEN_PROJECT.getTabs().clear();
BUTTON_CONFIRM.disableProperty().unbind();
selectedTabListener = null;
languageListener = null;
tabOpenNewProject = null;
tabOpenExistingProject = null;
stage = null;
getChildren().clear();
}
private void addLanguageListener() {
this.languageBundle.addListener(languageListener);
}
private void languageChange(ObservableValue<? extends ResourceBundle> observable, ResourceBundle oldValue, ResourceBundle newValue) {
reloadElements();
}
private String getValueFromKey(String key) {
return this.languageBundle.getValue().getString(key);
}
private void reloadElements() {
// Nothing to do
}
public void setStage(Stage stage) {
this.stage = stage;
}
private void selectedTabChanged(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
if (newValue.equals(tabOpenNewProject)) {
BUTTON_CONFIRM.setText(getValueFromKey(Keys.CREATE));
} else if (newValue.equals(tabOpenExistingProject)) {
BUTTON_CONFIRM.setText(getValueFromKey(Keys.OPEN));
}
}
}
For loading FXML files I use Singleton Class ScreenManager. This method is called to load this Dialog :
public void showNewDialog( FilesFXML fxml) {
FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml.toString()), context.getBundleValue());
try {
Stage dialogStage = new Stage();
AnchorPane dialogwindow = (AnchorPane) loader.load();
FXMLDialogController controller = loader.getController();
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(this.getStage());
Scene scene = new Scene(dialogwindow);
dialogStage.setScene(scene);
dialogStage.setResizable(false);
controller.setStage(dialogStage);
dialogStage.showAndWait();
} catch (Exception ex) {
log.error(ex.getMessage());
log.error(ex.getCause());
ex.printStackTrace();
}
}
I was checked it in VisualVM and I see one 1 of this controller and 2 lambdas ( I suppose it consiste initialization of 2 listener)
But event clear function is called this dialog is still in memory and cannot be garbage collected. I have no more idea how to force removing it. It is reallegrave, because it consist all of my Controllers.
I'm pretty confused what you are asking and what you are talking about. Nevertheless, if that dialog window is open, there is no way it can be garbage collected.
The JavaFX main API is holding a strong reference of the stage (maybe the scene too).
The stage/scene is holding strong reference of all the nodes specified in your FXML file.
Some of those nodes are holding strong reference of the controller because you have specified action event handlers in the controller.
In order to make the controller eligible for garbage collection, you need to break this chain somewhere.
The easiest way is to close the dialog window. When the window is closed, because the JavaFX engine does not need to manage render pulses anymore, it will release its reference to the stage. At that point, the whole thing under that stage is eligible for garbage collection, if nothing else (that itself is not eligible for garbage collection) is holding strong references of them.

JavaFX Table Columns, SceneBuilder Not Populating

I've been looking at tutorials, and I can't seem to get a table to populate.
I'm using net beans and scenebuilder too.
Any help would be greatly appreciated! been struggling for 5 hours.
Here is my code for the Controller class:
public class FXMLDocumentController implements Initializable {
#FXML
private TableView<Table> table;
#FXML
private TableColumn<Table, String> countriesTab;
/**
* Initializes the controller class.
*/
ObservableList<Table> data = FXCollections.observableArrayList(
new Table("Canada"),
new Table("U.S.A"),
new Table("Mexico")
);
#Override
public void initialize(URL url, ResourceBundle rb) {
countriesTab.setCellValueFactory(new PropertyValueFactory<Table, String>("rCountry"));
table.setItems(data);
}
}
Here is my code for the Table
class Table {
public final SimpleStringProperty rCountry;
Table(String country){
this.rCountry = new SimpleStringProperty(country);
}
private SimpleStringProperty getRCountry(){
return this.rCountry;
}
}
Here is my main:
public class Assignment1 extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
For PropertyValueFactory to find the property the item class (i.e. Table in this case) needs public as access modifier, not package private. The method returning the property needs to be public as well.
Furthermore the correct name for the method returning the property itself is <nameOfProperty>Property according to the conventions required for PropertyValueFactory to work.
Also since the actual type of the property is an implementation detail, it would be better design to use StringProperty as return type instead of SimpleStringProperty
public class Table {
private final SimpleStringProperty rCountry;
public Table(String country){
this.rCountry = new SimpleStringProperty(country);
}
public StringProperty rCountryProperty() {
return this.rCountry;
}
}
In case you used these modifiers to prevent write access to the property, you can still achieve this effect by using a ReadOnlyStringWrapper and return a ReadOnlyStringProperty:
public class Table {
private final ReadOnlyStringWrapper rCountry;
public Table(String country){
this.rCountry = new ReadOnlyStringWrapper (country);
}
public ReadOnlyStringProperty rCountryProperty() {
return this.rCountry.getReadOnlyProperty();
}
}
In case there is no write access to the property at all, simply using a getter for the property is enough. You do not need to use a StringProperty at all in this case:
public class Table {
private final String rCountry;
public Table(String country){
this.rCountry = country;
}
public String getRCountry() {
return this.rCountry;
}
}

how to share data between two stages in javafx

I have two fxml window login and main window.Their respective controllers are given below:
public class MainwindowController extends Stage implements Initializable {
#FXML private Button Send;
#FXML private TextField txtBcast;
#FXML private ListView listviewUsers;
#FXML Label lblDisplayName;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
ObservableList<String> chat =FXCollections.observableArrayList ("default");
listviewUsers.setItems(chat);
}
public void setLblName(String msg){
lblDisplayName.setText(msg);
}
#FXML public void ActionSend(ActionEvent e){
send();
txtBcast.setText("");
}
private void send() {
if (txtBcast.getText().isEmpty())
return;
// chatManager.sendPublicMsg(format,txtBcast.getText());
}
/**
*
* #param e
* #throws Exception
*/
#FXML public void ActionUserSelected( MouseEvent e) throws Exception{
// String lineRest = e.getActionCommand();
if(e.getClickCount()==2)
{
if(!listviewUsers.getSelectionModel().isEmpty())
{
String str=(String)listviewUsers.getSelectionModel().getSelectedItem();
Parent main= FXMLLoader.load(getClass().getResource("/letschat/fxwindows/Usertab.fxml"));
Scene scene = new Scene(main);
Stage stage = new Stage();
stage.setTitle(str);
stage.setScene(scene);
stage.show();
}
else { JOptionPane.showMessageDialog(null, "Oops! it seems you are trying to click the list view"); }
}
//Stage pstage = (Stage)listUsers.getScene().getWindow();
//pstage.close();
}
}
And
public class LoginwindowController extends Stage implements Initializable {
#FXML private LoginwindowController loginwindowController;
#FXML private MainwindowController mainwindowController;
#FXML private Button btnSignIn;
#FXML private TextField txtDisplayName;
#FXML private ToggleGroup Gender;
#FXML private ComboBox comboStatus;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
ObservableList<String> items =FXCollections.observableArrayList ("Online","Offline");
comboStatus.setItems(items);
writeToTextField();
}
public void writeToTextField() {
String username = System.getProperty("user.name");
txtDisplayName.setText(""+ username);
}
#FXML protected void ActionSignIn(ActionEvent event) throws Exception {
mainwindowController.setLblName(txtDisplayName.getText());
InetAddress addr = InetAddress.getLocalHost();
if(addr.isLoopbackAddress())
{
Dialogs.create().message("Oops! It seems you are not connected to any network..\n :(").showError();
}
else{
start(txtDisplayName.getText());// start chat manager
Parent root= FXMLLoader.load(getClass().getResource("/letschat/fxwindows/Mainwindow.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setTitle("LetsChat-Welcome "+ txtDisplayName.getText());
// Context.getInstance().setDisplayName(txtDisplayName.getText());
stage.setScene(scene);
stage.getIcons().add(new Image("/letschat/images/logo.png"));
Stage pstage = (Stage)btnSignIn.getScene().getWindow();
stage.show();
pstage.close();
}
}
private void start(String name) {
try {
ChatManager ic = new ChatManager(name);
ic.start();
} catch (Exception ex) {
Dialogs.create().message( "Could not start the chat session\nCheck that there no other instances running :(").showError();
}
}
}
I want the label lblDisplayName in main window updated with text from txtDisplay Name in login window when user clicks signin button.can someone help how to do so..soon plz
There are various ways to do this, in your case Login will create the other stage so an easy way is to create a new FXML loader (variable name: myLoader) and, if you want to pass the username of the user as constructor argument you can use myLoader.setControllerFactory and as return:
return clazz == MyController.class ? new MyController(userName) : null;
MyController is the name of the Controller where you want to read the username
If you want to use set methods, with getController you get the controller instance and call the set method (e.g, myController.setUsername());
To create a custom FXML
FXMLLoader myLoader = new FXMLLoader(<if you use relative paths, here you should pass the position);
remember to call the load() because the URI overload is static. (i.e, use getResourceAsStream).
If your application is large and complex, you could use EventBus (which I prefer everywhere..)
I'm not sure I completely understand the relationship between the two controllers, and which are the FXML files that correspond to the controllers, but it looks like the LoginWindowController loads MainWindow.fxml, and I'm guessing that MainWindowController is the controller for MainWindow.fxml.
In that case, you can just do
#FXML protected void ActionSignIn(ActionEvent event) throws Exception {
InetAddress addr = InetAddress.getLocalHost();
if(addr.isLoopbackAddress())
{
Dialogs.create().message("Oops! It seems you are not connected to any network..\n :(").showError();
}
else{
start(txtDisplayName.getText());// start chat manager
FXMLLoader loader = new FXMLLoader(getClass().getResource("/letschat/fxwindows/Mainwindow.fxml"));
Parent root= loader.load();
MainWindowController mainWindowController = loader.getController();
mainWindowController.setLblName(txtDisplayName.getText());
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setTitle("LetsChat-Welcome "+ txtDisplayName.getText());
// Context.getInstance().setDisplayName(txtDisplayName.getText());
stage.setScene(scene);
stage.getIcons().add(new Image("/letschat/images/logo.png"));
Stage pstage = (Stage)btnSignIn.getScene().getWindow();
stage.show();
pstage.close();
}
}

Resources