I have a class Foo which just load the FXML and create the scene.
In the FXML, I set the controller to be FooController (fx:controller="FooController")
And I add a MenuButton:
<MenuButton fx:id="menuButton" layoutX="264.1875" layoutY="146.5" mnemonicParsing="false" text="MenuButton" />
And I try to set the menuButton in the FooController:
public class FooController implements Initializable{
#FXML
final MenuButton menuButton = new MenuButton("Modalities");
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
final ObservableList<CheckMenuItem> listFilter = FXCollections.observableArrayList();
final MenuButton menuButton = new MenuButton("Modalities");
CheckMenuItem item1 = new CheckMenuItem("T1");
CheckMenuItem item2 = new CheckMenuItem("T1C");
CheckMenuItem item3 = new CheckMenuItem("T2");
listFilter.addAll(item, item2, item3);
menuButton.getItems().addAll(listFilter);
menuButton.setId("menuButton");
}
}
But despite of setting everything for the MenuButton it doesn't display any of the CheckMenuItems in the GUI.
How can I load those items in menuButton defined in the FXML?
Never set an #FXML initialized value to a new value.
In your posted code, you are doing this twice, when you should not be doing it at all.
The FXMLLoader will create new items within the hierarchy of the component it instantiates and inject references to these new items into your controller. If you then set these references to new values, the new values will never be included in the displayed component hierarchy unless you specifically add them there, which kind of defeats the purpose of using FXML in the first place as it ignores things defined in your FXML file.
What you should have is:
public class FooController {
#FXML
MenuButton menuButton;
public void initialize() {
menuButton.getItems().addAll(
FXCollections.observableArrayList(
new CheckMenuItem("T1"),
new CheckMenuItem("T1C"),
new CheckMenuItem("T2")
)
);
}
}
Also note that if your CheckMenuItems in the above code are static rather than a dynamic list, then you could just define them all in your FXML document instead of creating them in code.
Note: This is a duplicate question and has been asked before (not the exact question, but the substance of it), but my google skills couldn't dig up some of the duplicates.
Related
Okay so i am very rusty on my java and even more on javafx. so i got a choicebox "categoryDrop" that when the value of the choicebox change i want to trigger this event that then takes the value of the choicebox and compare to an object "Folder" categorylist wich is an attribute it has.
here is my code
#FXML
private void folderByCategory(ActionEvent event) {
System.out.println("här1");
TreeItem<DocumentObject<?>> treeRoot = new TreeItem<>(new Folder());
for (Folder folder : logic.getFolderList()) {
if(f.getCategoryList().contains(categoryDrop.valueProperty())){
System.out.println("här2");
TreeItem<DocumentObject<?>> newFolders = new TreeItem<>(folder);
for(FileReference file : folder.getFileList()){
System.out.println(file.getName());
TreeItem<DocumentObject<?>> fileNode = new TreeItem<>(file);
newFolders.getChildren().add(fileNode);
}
treeRoot.getChildren().add(newFolders);
treeRoot.setExpanded(true);
}
treeNav.setRoot(treeRoot);
}
}
But then when i looked in scenebuilder i didnt see any good way to implement the method so it triggers when it changes. Anyone know a better way to do this? should i use a listener instead maybe?
ChoiceBox has an onAction property, so in FXML you can simply assign this controller method to this property:
<ChoiceBox fx:id="categoryDrop" onAction="#folderByCategory" />
Unfortunately, the current version of Scene Builder does not support this property, so you cannot set this directly from Scene Builder. There is a current issue filed for this.
Some workarounds are:
Edit the FXML manually to add the onAction attribute, as above.
Use a ComboBox instead of a ChoiceBox. The functionality is similar (though not identical) and a ComboBox will likely do what you need. Scene Builder does support the onAction property of a ComboBox.
Register the handler in the controller's initialize() method instead. All you need is
#FXML
private ChoiceBox<...> categoryDrop ;
public void initialize() {
categoryDrop.setOnAction(this::folderByCategory);
// existing code ...
}
#FXML
private void folderByCategory(ActionEvent event) {
// existing code...
}
First time asker, so please excuse any missing/wrong-placed Information and of course my bad english. Gotta say that as a german. ;)
Simple and short, I try to add Nodes into a Dialog by using
dialogPane.getChildren.add()
Code:
The Class signature:
public class VerteilDialog extends Dialog<Void>
Declaration of the needed items:
private Label _jlVersionNum;
private TextField _tfVersionNum;
private Label _jlSonstiges;
private TextArea _taSonstiges;
ButtonType btAbbrechen = new ButtonType("Abbrechen", ButtonData.CANCEL_CLOSE);
ButtonType btOk = new ButtonType("Ok", ButtonData.OK_DONE);
getDialogPane().getButtonTypes().add(btAbbrechen);
getDialogPane().getButtonTypes().add(btOk);``
And initialization of those in the contructor:
_jlVersionNum = new Label("Versionsnummer:");
_tfVersionNum = new TextField("4.10.x");
_jlSonstiges = new Label("Sonstiges:");
_taSonstiges = new TextArea();
_jlEinDatum = new Label("Einsatz am:");
And I add the Items like this:
getDialogPane().getChildren().addAll(_tfEinDatum, _jlVersionNum, _tfVersionNum, _jlSonstiges, _taSonstiges);
and Show the dialog
showAndWait();
Calling the Dialog happens here:
import javafx.application.Application;
import javafx.stage.Stage;
public class MainKlasse extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage arg0) throws Exception {
new VerteilDialog();
}
}
I'd expect the items to be added properly without further Problems, but (and that's why I am actually here):
The Dialog is displayed without further Errors or any exceptions, but it's empty apart from the Buttons, "Ok" and "Abbrechen".
Edit: Added call of showAndWait(); that I forgot while writing the question.
After a bit of tinkering, I found a solution.
getDialogPane().getChildren.addAll() does not add Nodes so that they get visible. One should use a Pane to add Nodes to and set the Pane as Content by using getDialogPane().setContent
I am trying to make it such that I can create a new tab for my TabPane from within another tab but I am having some difficulty. Currently I have the TabPane set up in the "main-window.fxml" with the corresponding MainWindowController. I have a tab within this TabPane which, via fx:include, displays "mainTab.fxml" to the scene graph, controlled by MainTabController. Now from within the "mainTab" I want a button to be able to add an additional tab to the TabPane, but since this is requires a reference to the TabPane in "main-window", I have created a static method in "main-window". When the run the code below I get a NullPointerException on this line in the MainWindowController:
mainTabPane.getTabs().add(new Tab(team.getTeamName()));
Could someone please tell me as to why it is giving this exception and how I can begin to work around it?
main-window.fxml:
<TabPane fx:id="mainTabPane">
<tabs>
<Tab fx:id="mainTab" text="Main" closable="false">
<fx:include source="mainTab.fxml" fx:id="mainWindowTab" alignment="CENTER"/>
</Tab>
</tabs>
</TabPane>
mainTab.fxml (the event handler for the button):
#FXML
public void handleSubmit() {
String teamName = teamNameTextField.getText();
Roster roster = rosterComboBox.getValue();
int startWeek = spinner.getValue();
Team newTeam = new Team(teamName, startWeek, roster);
TeamData.addTeam(newTeam);
MainWindowController controller = new MainWindowController();
controller.createTeamTab(newTeam);
}
MainWindowController:
public class MainWindowController {
#FXML
private TabPane mainTabPane;
public void createTeamTab(Team team) {
mainTabPane.getTabs().add(new Tab(team.getTeamName()));
}
}
Your code doesn't work because you are not calling createTeamTab(...) on the controller: you are calling it on another instance of MainWindowController that you created. (The fields annotated #FXML are initialized in the controller instance by the FXMLLoader when the FXML is loaded: for fairly obvious reasons they will not be set to the same values in arbitrary other instances of the same class.) You need to get a reference to the controller you are using for the main tab, and pass it a reference to the main controller.
You didn't tell us the class name for the controller of mainTab.fxml: I will assume it is MainTabController (so just change it to whatever class name you actually use).
In MainWindowController, do:
public class MainWindowController {
#FXML
private TabPane mainTabPane;
#FXML
// fx:id of the fx:include with "Controller" appended
private MainTabController mainWindowTabController ;
public void initialize() {
mainWindowTabController.setMainWindowController(this);
}
public void createTeamTab(Team team) {
mainTabPane.getTabs().add(new Tab(team.getTeamName()));
}
}
and then in MainTabController do
public class MainWindowController {
private MainWindowController mainWindowController ;
public void setMainWindowController(MainWindowController mainWindowController) {
this.mainWindowController = mainWindowController ;
}
#FXML
public void handleSubmit() {
String teamName = teamNameTextField.getText();
Roster roster = rosterComboBox.getValue();
int startWeek = spinner.getValue();
Team newTeam = new Team(teamName, startWeek, roster);
TeamData.addTeam(newTeam);
mainWindowController.createTeamTab(newTeam);
}
}
I'm defining the TextArea in my controller class like this:
#FXML
private TextArea txtAreaStatus;
And I'm trying to append text to the TextArea using this code:
#FXML
public void clickGo (ActionEvent event) {
txtAreaStatus = new TextArea("");
txtAreaStatus.appendText("data");
System.out.println("clicked");
}
I'm really confused as to why my text area is not updating. No errors whatsoever.
When I click the button, clicked gets printed on the screen.
What am I doing wrong?
Whenever you are using FXML and Controller combination, controls references are annotated with #FXML in the controller. The objects are injected into their respective references when the fxml is loaded. Therefore you don't need to do define a new object for them.
In your code you need to remove :
txtAreaStatus = new TextArea("");
because this makes you loose the reference to the object of TextField on the scene and defines a new Textfield object (which is not on the scene). You are later trying to do operations on this new object.
My question is simple, is there any way of making a bidirectional bind between a choicebox's items and an arraylist (that can be added to and removed from, from another class)
My SettingsService contains a simple ArrayList containing User objects. New items can be added from other classes and places in my application.
If I add a user to this list, how can the new item automatically appear in the choicebox?
Example:
Viewmodel
public class ViewModel {
private SettingsService settings = new SettingsService();
public final ObjectProperty<ObservableList<User>> userChoiceBoxItems = new SimpleObjectProperty<>();
public ViewModel() {
userChoiceBoxItems.setValue(FXCollections.observableArrayList(settings.getUsers()))
}
}
View
public class View {
private ViewModel viewModel = new ViewModel();
#FXML
ChoiceBox<User> userChoiceBox;
#FXML
public void initialize() {
userChoiceBox.itemsProperty().bindBidirectional(viewModel.userChoiceBoxItems);
}
Thanks for the help
create a new ObservableList as
ObservableList<User> tempList = FXCollections.observableArrayList()
and add all items to the list as
templist.addAll(userChoiceBoxItems)
and then bidirectionally bind