JAVAFX Tree view with different context menu - javafx

I want to create context menu for treeitems in a treeview. The thing is I want to display different context menu for each treeItem. How to implement this?
Foe example I want to create "Add Employee" for Acc Dept and "Add Supporter" for IT support.
Based on name of the treeitem the context menu needs to be displayed.

public TreeModel() {
MenuItem addMenuItem = new MenuItem("Create Tab");
addMenu.getItems().add(addMenuItem);
addMenuItem.setOnAction(new EventHandler() {
#Override
public void handle(Event t) {
TreeItem newEmployee =
new TreeItem<>("New Tab");
getTreeItem().getChildren().add(newEmployee);
}
});
contextMenuProperty().bind(
Bindings.when(Bindings.equal(itemProperty(),"TABS"))
.then(addMenu)
.otherwise((ContextMenu)null));
}
This works. #James thanks a lot for your excellent article :)

Related

JavaFX MenuItem, handling the event

I'm developing an small application and I have a problem when creating the menu bar.
This is my start method:
public void start(#SuppressWarnings("exports") Stage prymaryStage) throws Exception {
// Stats menu
Menu statsMenu = new Menu("Stats");
// PairName menu
Menu pairNameMenu = new Menu("Choose pair");
// Stats Menu items
MenuItem gStats = new MenuItem("General stats");
// Pair list
ArrayList<String> pairNameList = DatabaseMethods.returnPairNameList();
// PairName items (probably i will have to change)
for (String item : pairNameList) {
pairNameMenu.getItems().add(new MenuItem(item));
}
statsMenu.getItems().addAll(gStats, pairNameMenu);
// Main menu bar
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(statsMenu);
// BorderPane settings
BorderPane borderPane = new BorderPane();
borderPane.setTop(menuBar);
Scene scene = new Scene(borderPane, 1200, 800);
prymaryStage.setTitle("English minimal pair training");
prymaryStage.setScene(scene);
prymaryStage.show();
}
The problem I have is in this part of the code:
ArrayList<String> pairNameList = DatabaseMethods.returnPairNameList();
// PairName items (probably i will have to change)
for (String item : pairNameList) {
pairNameMenu.getItems().add(new MenuItem(item));
}
I was trying to create the items of a submenu from an ArrayList. This data is fetch from a database and the data is returned in form of an ArrayList. I didn't find any other way to do the menu items than pairNameMenu.getItems().add(new MenuItem(item)); inside the for loop.
Now I want to handle the click in the items but I don't know how to do it. I've tried with .setOnAction but Eclipse says the .add(new MenuItem(item)) can't be use in that case and recomends .addAll and the same happens, Eclipse says that's an error and recomends .add
I tried to add this code after new MenuItem(item)
.addEventHandler(new EventHandler<ActionEvent>() {
public void handle(ActionEvent even) {
}
})
But it didn't work either.
I'm pretty new to Java and JavaFX, this is my first project so sorry if this is a very basic question.
Thank you for your time
You have to loop through pairNameMenu items after you have created and added all the items to pairNameMenu:
pairNameMenu.getItems().foreach((item) ->{
item.addEventHandler.....
....
....
});
or do something like below when creating the MenuItems:
for (String item : pairNameList) {
MenuItem tempMenuItem = new MenuItem(item);
tempMenuItem..addEventHandler.....
....
....
pairNameMenu.getItems().add(tempMenuItem);
}

How to Generate Message According to Values in Multiple Fields?

I am building an application using JavaFX. What I am trying to do is generate a message according to the user input values. So there are one text-field and one combo-box and one check-box per row and there are many rows like the following.
Let's say I will generate three different messages according to the user values. So I need to check whether those fields are empty or not and check each field's value to generate a specific message. Checking fields are okay for just three rows like the above. But I have 10 fields. So I have to check each and generate or append my own message. And also if the user checked the check-box need to group all checked row values. So what I am asking is there any good way (best practice) to achieve what I need or an easy one also? I have tried with HashMap and ArrayList. But those are not working for this.
Really appreciate it if anybody can help me. Thanks in advance.
I would probably recommend a custom node that you create on your own like below. This example is not supposed to have the same functionality as your application but just to show how to create and use custom nodes. I kept your idea in mind when creating this example it has your textfield combobox and checkbox and they are a little easier to manage. Give it a run and let me know if you have any questions
public class Main extends Application {
#Override
public void start(Stage stage) {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
ArrayList<String> itemList = new ArrayList<>(Arrays.asList("Dog", "Cat", "Turkey"));
ArrayList<HBoxRow> hBoxRowArrayList = new ArrayList<>();
for (int i = 0; i<3; i++) {
HBoxRow hBoxRow = new HBoxRow();
hBoxRow.setComboBoxValues(FXCollections.observableList(itemList));
hBoxRowArrayList.add(hBoxRow);
vBox.getChildren().add(hBoxRow.gethBox());
}
Button printTextfieldsButton = new Button("Print Textfields");
printTextfieldsButton.setOnAction(event -> {
for (HBoxRow hBoxRow : hBoxRowArrayList) {
System.out.println("hBoxRow.getTextFieldInput() = " + hBoxRow.getTextFieldInput());
}
});
vBox.getChildren().add(printTextfieldsButton);
stage.setScene(new Scene(vBox));
stage.show();
}
//Below is the custom Node
public class HBoxRow {
HBox hBox = new HBox();
ComboBox<String> comboBox = new ComboBox<>();
TextField textField = new TextField();
CheckBox checkBox = new CheckBox();
public HBoxRow(){
hBox.setAlignment(Pos.CENTER);
textField.setPrefWidth(150);
comboBox.setPrefWidth(150);
checkBox.setOnAction(event -> {
textField.setDisable(!textField.isDisabled());
comboBox.setDisable(!comboBox.isDisabled());
});
hBox.getChildren().addAll(checkBox, textField, comboBox);
}
public void setComboBoxValues(ObservableList observableList) {
comboBox.setItems(observableList);
}
public HBox gethBox(){
return hBox;
}
public String getTextFieldInput(){
return textField.getText();
}
}
}

Javafx : ComboBoxTableCell - how to select a value in one click?

I have a TableView with a ComboBoxTableCell, when using the default implementation the user have to click three times to select a value from of the ComboBox's list.
I want when the user clicks on the cell to show the combo box list. I based my solution on this one:
JavaFX editable ComboBox in a table view
The cell does get into edit mode (startEdit() is called) but it takes another click to show the list of values, what am I missing?
table.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) ->
{
if (table.getEditingCell() == null)
{
TablePosition focusedCellPos = table.getFocusModel().getFocusedCell();
table.edit(focusedCellPos.getRow(), focusedCellPos.getTableColumn());
}
});
Thanks.
Interesting problem - bubbling up again after quite a while :)
Looks like the approach of the OP is indeed working (as of fx11, some bugs around its editing seem to be fixed) - with a little help from the combo cell:
start editing in a single click handler on the tableView (from OP)
extend ComboBoxTableCell and override its startEdit to open the dropDown
Code snippet:
// set editable to see the combo
table.setEditable(true);
// keep approach by OP
table.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
TablePosition<Person, ?> focusedCellPos = table.getFocusModel()
.getFocusedCell();
if (table.getEditingCell() == null) {
table.edit(focusedCellPos.getRow(),
focusedCellPos.getTableColumn());
}
});
// use modified standard combo cell shows its popup on startEdit
firstName.setCellFactory(cb -> new ComboBoxTableCell<>(firstNames) {
#Override
public void startEdit() {
super.startEdit();
if (isEditing() && getGraphic() instanceof ComboBox) {
// needs focus for proper working of esc/enter
getGraphic().requestFocus();
((ComboBox<?>) getGraphic()).show();
}
}
});
Maybe not the cleanest solution to this problem, but I found a workaround to make the ComboBoxTableCells drop down its menu in just 1 click:
column.setCellFactory(new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {
#Override
public TableCell<Person, String> call(TableColumn<Person, String> column) {
ComboBoxTableCell cbtCell = new ComboBoxTableCell<>(cbValues);
cbtCell.setOnMouseEntered(new EventHandler<Event>() {
#Override
public void handle(Event event) {
// Without a Person object, a combobox shouldn't open in that row
if (((Person)((TableRow)cbtCell.getParent()).getItem()) != null) {
Robot r = new Robot();
r.mouseClick(MouseButton.PRIMARY);
r.mouseClick(MouseButton.PRIMARY);
}
}
});
return cbtCell;
}
});
PS: I know that this topic is a bit old, but I also stumbled upon this problem recently and could not find any working solution to it online. As I sad, it's not the cleanest workaround, but at least it does its job. ;)

Create JavaFX ComboBox with custom Popup

I want to write a ComboBox with a custom Node object inside its Popup (rather than the common ListView). ColorPicker and DatePicker are good examples, which are the other two implementations of ComboBoxBase. I had thought I could easily extend ComboBoxBase, too, but since there is no popupProperty or popupFactory I don't know how to set the content. How else is it meant to be done? Or how ColorPicker and DatePicker do this?
ComboBoxPopupControl which extends ComboBoxBaseSkin contains getPopupContent(). That's the method you are looking for. In your own skin implementation, which extends one of the ComboBoxSkins, you can return the popup content you like (although it's not recommended to use private API)
public class CustomComboBox<T> extends ComboBox<T> {
#Override
protected Skin<?> createDefaultSkin() {
return new CustomComboBoxSkin<>(this);
}
}
public class CustomComboBoxSkin<T> extends ComboBoxPopupControl<T> {
public CustomComboBoxSkin(ComboBox<T> comboBox) {
super(comboBox, new CustomComboBoxBehaviour<>(comboBox));
}
#Override
public Node getPopupContent() {
return new Rectangle(150, 200);
}
// inherited methods ...
}
I used ComtextMenu to replace the commbox's popup like this:
ContextMenu menu = new ContextMenu();
MenuItem item = new MenuItem();
item.setGraphic(new Lable("test"));
menu.getItems.add(item);
commbox.setContextMenu(null);
commbox.setContextMenu(menu );
commbox.getContextMenu().show(comboBox, Side.BOTTOM, 0, 0);
It works fine.

How an action can be performed when clicking on a menu item?

I am doing a project in javafx using Netbeans IDE. I am new to javafx. I have a menu bar in my project. I need to open a new page on the same windows when clicked on each menu item(not new scene). The code is given below :
private VBox addVBox1() {
final VBox vbox = new VBox();
vbox.setPadding(new Insets(20,40,30,4));
vbox.setSpacing(10);
MenuBar menuBar = new MenuBar();
Menu menuFile1 = new Menu("ADD");
Menu menuFile2 = new Menu("EDIT");
Menu menuFile3 = new Menu("VIEW");
Menu menuFile4 = new Menu("HELP");
MenuItem add1 = new MenuItem("ENTER STUDENT DETAILS");
MenuItem add2 = new MenuItem("ENTER C-MARK");
MenuItem add3 = new MenuItem("ENTER ATTENDANCE");
MenuItem add4 = new MenuItem("EDIT STUDENT DETAILS");
MenuItem add6 = new MenuItem("EDIT C-MARK");
MenuItem add8 = new MenuItem("EDIT ATTENDANCE");
MenuItem add10 = new MenuItem("STUDENT DETAILS");
MenuItem add11 = new MenuItem("C-MARK");
MenuItem add12 = new MenuItem("ATTENDANCE");
MenuItem add13 = new MenuItem("VIEW HELP");
add1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
//...WHAT TO INCLUDE HERE ?
}
});
menuFile1.getItems().addAll(add1,add2,add3);
menuFile2.getItems().addAll(add4,add6,add8);
menuFile3.getItems().addAll(add10,add11,add12);
menuFile4.getItems().addAll(add13);
menuBar.getMenus().addAll(menuFile1,menuFile2,menuFile3,menuFile4);
vbox.getChildren().addAll(menuBar);
return vbox;
}
In my project, I open new pages when clicking on buttons. Its code is:
btn2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
((Stage)btn2.getScene().getWindow()).setScene(new Scene(new Login()));
}
});
Is it possible to implement this code in case of menu item ? How should I edit this code to perform an action when clicked on a menu item ?
I don't know exactly what you mean by a new page. There is a Pagination control, but I don't think you mean that. Here's how to add a TextArea but you have to design the UI and choose your own controls.
add1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
vbox.getChildren().add(new TextArea());
}
});
This is how to make a new window but you may want to ask a question about designing dialog boxes. Here's a SO answer https://stackoverflow.com/a/14168238/2855515
add1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
Stage stage = new Stage();
Scene scene = new Scene(new VBox());
stage.setTitle("popup");
stage.setScene(scene);
stage.show();
}
});
I think this question has not been answered correctly and the question has been misinterpreted.
TomJ asked:
Is it possible to implement this code in case of menu item?
When he says "menu item", Does he mean Menu or MenuItem? He's clearing showing the correct code for how to do it for a MenuItem. I think he's asking about how to do that same thing for a Menu. I tried doing this for a Menu, and the code for invoking a handler on a Menu is slightly different than doing it for a MenuItem.
Here's a simple code example where the execute method is called when the Execute Menu is clicked:
Menu viewMenu = new Menu("View");
MenuItem viewJobs = new MenuItem("Jobs");
viewJobs.setOnAction(viewJobsAction);
MenuItem viewFileSelection = new MenuItem("File Selection");
viewFileSelection.setOnAction(e->{viewFileSelection());
viewMenu.getItems().addAll(viewJobs, viewFileSelection);
Menu execute = new Menu("Execute");
execute.onShownProperty().setValue(e->{execute());
// if the following line is not added, the onShownProperty event handler
// will never be called!
execute.getItems().addAll(new MenuItem());
Menu help = new Menu("Help");
MenuItem helpItem = new MenuItem("Help");
helpItem.setOnAction(e->{showHelp()}
MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(e->{showAbout()}
help.getItems().addAll(helpItem,aboutItem);
menubar.getMenus().addAll(viewMenu, execute, help);
It's necessary to have a bogus MenuItem added to the Execute Menu for this to work. For Menu, it's better to use the onShownProperty or onShowingProperty rather than using the setOnAction. Any of them will work, but the setOnAction will require a second click before the handler will be called.
The JavaDoc for onShowingProperty for Menu says:
Called just prior to the ContextMenu being shown, even if the menu has
no items to show. Note however that this won't be called if the menu
does not have a valid anchor node.
It sounds like the code should work without any MenuItems added, but it doesn't. It says however that the call won't be made if the menu doesn't have a valid anchor node. I'm not sure what an anchor node is, and I couldn't find any documentation about how to add an anchor node to a menu. Adding the bogus empty MenuItem clearly made the Execute Menu have a valid anchor node. If someone knows more about anchor nodes, please reply and explain it, but the code example I gave works acceptably.

Resources