How to remove MenuItems from MenuButtons with Javafx - java

I am trying to make a dynamically sized MenuButton.
I am designing a library program. Books go on Shelves. Over the course of the program, the number of shelves could increase or decrease.
I want to make a menu Button that can reflect the shelves in the library - the set of MenuItems should increase if the number of shelves increase and decrease if the number of shelves decrease.
This is my current code. However, it doesn't remove any MenuItems. Also, it duplicates all the MenuItems already included.
previous code omitted…
//the button “shelfBtn.getItems” is a MenuButton defined elsewhere
Button btn = new Button(“Refresh”);
btn.setTranslateX(-20);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for(String shelf : shelfs){
MenuItem newShelf = new MenuItem(shelf);
newShelf.setOnAction(new EventHandler<ActionEvent() {
#Override
public void handle(ActionEvent event) {
// ignore this
shelfField.setText(shelf);
}
});
shelfBtn.getItems().add(newShelf);
}
}
});
remaining code omitted…
I have also tried using iteration to limit extra menuItems from being created - to no avail.
Additionally:
1) Is there a way to just delete a menuItem?
2) Is there a way to clear a MenuButton?
Thanks

Simply modifiy the items ObservableList:
#Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
for (int i = 0; i < 26; i++) {
listView.getItems().add(Character.toString((char) ('a'+i)));
}
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
MenuButton menuButton = new MenuButton();
Button btn = new Button("Modify");
btn.setOnAction((ActionEvent event) -> {
// create menu items from selection
menuButton.getItems().clear();
for (String s : listView.getSelectionModel().getSelectedItems()) {
menuButton.getItems().add(new MenuItem(s));
}
});
Scene scene = new Scene(new VBox(listView, menuButton, btn));
primaryStage.setScene(scene);
primaryStage.show();
}
As with any List there are multiple ways to remove and add elements to the list, like add, remove, clear, ect.
Adding duplicates can be prevented by using a Set, e.g.
Set<String> items = new shelfBtn.getItems().stream()
.map(MenuItem::getText)
.collect(Collectors.toCollection(HashSet::new));
for(String shelf : shelfs){
if (items.add(shelf)) {
...
}
}

Related

how to actually hide Tab from TabPane with JavaFX

previously I was working on Java Swing and now I'm trying to work with JavaFX. My Java Swing code last time:
//These line of code is to call method that declared in ContentPage.java
contentPage.adminFeatureEnabled(adminEnabled);
contentPage.managerFeatureEnabled(managerEnabled);
and in my ContentPage.java
//By default, all feature (or tab) are enabled.
//This method is to remove register account if the user login into the system is manager and staff
public void adminFeatureEnabled(boolean a) {
if (!a) {
tabPane.removeTabAt(tabPane.indexOfComponent(registerAccount));
}
}
//This method is to remove register account and purchase order if the user who log into the system is staff
public void managerFeatureEnabled(boolean a) {
if(!a) {
tabPane.removeTabAt(tabPane.indexOfComponent(purchaseOrder));
}
}
and in my code:
if (role.equals("admin")){
contentPage.contentFrame.setTitle("Menu - Admin!");
contentPage.disUser.setEditable(true);
contentPage.chgRoles.setEnabled(true);
} else if(role.equals("manager")){
contentPage.contentFrame.setTitle("Menu - Manager!");
contentPage.chgRoles.setSelectedItem("manager");
adminEnabled = false;
}else if (role.equals("staff")){
contentPage.contentFrame.setTitle("Menu - Staff!");
contentPage.chgRoles.setSelectedItem("staff");
adminEnabled = false;
managerEnabled = false;
}
The code above will perform like this:
when the user login with admin account, all the feature (Tab) enabled
when the user login as manager, some feature (tab) will be hide
My current problem now:
I wanted the same feature as above in JavaFX but I don't know how as none of the method works as I wanted.
anyone can help me with this?
Simply modify the tabs list:
The following example adds/removes Tabs, when the CheckBoxes are (un)selected.
#Override
public void start(Stage primaryStage) {
Tab tab1 = new Tab("Tab 1", new Label("1"));
Tab tab2 = new Tab("Tab 2", new Label("2"));
TabPane tabPane = new TabPane();
tabPane.setPrefSize(400, 400);
CheckBox cb1 = new CheckBox("1");
CheckBox cb2 = new CheckBox("2");
cb1.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
tabPane.getTabs().add(0, tab1);
} else {
tabPane.getTabs().remove(tab1);
}
});
cb2.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
tabPane.getTabs().add(tab2);
} else {
tabPane.getTabs().remove(tab2);
}
});
Scene scene = new Scene(new VBox(new HBox(cb1, cb2), tabPane));
primaryStage.setScene(scene);
primaryStage.show();
}
It's been so long since the question asked, but this maybe helpful for someone.
You can try something like this.
you have a tabPane with three tabs tabOne, tabTwo and tabThree.
position index of tabs
tabOne - 0
tabTwo - 1
tabThree - 2
to hide tabTwo, you can use remove function and again reappear you can use set function.
to remove tab
tabPane.getTabs().remove(tabTwo);
set again with the relevant index to display at the correct location.
tabPane.getTabs().set(1, tabTwo);

JavaFX: Getting IDs of Dynamic created Button

I'm currently made an Form with JavaFX.
Always i press a Button, i call the "addAnswer()"-Method.
In that I create a RadioButton, a Label and a delete-Button, which i bundle in a HBox. All that HBoxes i pack in a vBox.
The Problem now is the delete-Button. I want to delte just THAT HBox in which the clicked Button is.
Here is my code:
public void addAnswer() {
this.rB = new RadioButton();
checkAnswer.getToggles().add(rB);
hBox = new HBox();
tF = new TextField();
delAnswer = new Button("Löschen");
delAnswer.setId(Integer.toString(counter));
hBox.getChildren().addAll(rB, tF, delAnswer);
hBox.setId(Integer.toString(counter));
delAnswer.setOnAction(e -> delAnswer(Integer.parseInt(hBox.getId())));
System.out.println(delAnswer.getId());
vBox.getChildren().addAll(hBox);
counter++;
}
public void delAnswer(int e){
vBox.getChildren().remove(delAnswer.getId());
}
i tried this one above but i realized, that all the delAnswers-Buttons have the same ID: the number of how often i pressed the add-Button.
Is there any solution where i can just select that one i pressed with that dynamic way? Cause i don't kow how often somebody will press or delete something.
Thanks
hbox is a field and this is why always the HBox last added is used. (hBox is evaluated, when lambda body is executed, not at the time of the lambda creation). This would be different, if you used a (effectively) final local variable:
final HBox hBoxLocal = hBox;
delAnswer.setOnAction(e -> delAnswer(Integer.parseInt(hBoxLocal.getId())));
However I'd like to present a different solution which would allow you to use the same EventHandler<ActionEvent> for all delete Buttons:
You can get the Node that triggered the event using getSource. From this Node you can get the parent, which is the HBox. You can remove this from the VBox using the remove(Object) method
delAnswer.setOnAction(e -> {
// get button
Node source = (Node) e.getSource();
// remove parent of button from VBox
vBox.getChildren().remove(source.getParent());
});
I think your problem is that you give the same event to all your button,Begin by creating a list that stores your buttons and then increments the value of the ID after affecting it to an item :
List<Button> buttons = new ArrayList<>();
/*
Create Button and call IDEvt method to create new event
for each button
*/
private void IDEvt(Button btn){
btn.setId(String.valueOf(IDRank));
btn.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println(btn.getId());
}
});
IDRank++;
}

JavaFX CheckBoxTree in popup of drop-down Button

In order for the end-user to constrain a search to some columns of the main TableView, I needed a treeview with checkboxes.
I decided to embed this TreeView in a popup, showing on click on a custom button.
I have created the following class, inspired from the question:
Java FX8 TreeView in a table cell
public class CustomTreeMenuButton extends MenuButton {
private PopupControl popup = new PopupControl();
private TreeView<? extends Object> tree;
private CustomTreeMenuButton me = this;
public void setTree(TreeView<? extends Object> tree) {
this.tree = tree;
}
public CustomTreeMenuButton() {
super();
this.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (!popup.isShowing()) {
Bounds b = me.localToScreen(me.getBoundsInLocal());
double x = b.getMinX();
double y = b.getMaxY();
popup.setAutoHide(true);
// popup.setAutoFix(true);
popup.setAnchorX(x);
popup.setAnchorY(y);
popup.setSkin(new Skin<Skinnable>() {
#Override
public void dispose() {
}
#Override
public Node getNode() {
return tree;
}
#Override
public Skinnable getSkinnable() {
return null;
}
});
popup.show(me.getScene().getWindow());
}
}
});
}
}
The tree I am working with contains CheckBoxTreeItem objects, and while the popup is working, there is some weird blur on all checkboxes, whenever the focus is not on a checkbox. (See GIF below)
First, I was thinking it was maybe an antialiasing problem, but popup.getScene().getAntiAliasing().toString() returns DISABLED
Then, I saw that non integer anchor points could cause problems. However popup.setAutoFix(true) did nothing, nor did the following:
popup.setAnchorX(new Double(x).intValue());
popup.setAnchorY(new Double(y).intValue());
It might be worth noting that I am working with FXML.
How can I get sharp checkboxes regardless of their focus ?
I would suggest a built-in control, CustomMenuItem, rather than reinventing the wheel:
A MenuItem that allows for arbitrary nodes to be embedded within it,
by assigning a Node to the content property.
An example
// Create the tree
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("All stuff");
rootItem.setExpanded(true);
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setEditable(true);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
for (int i = 0; i < 8; i++) {
final CheckBoxTreeItem<String> checkBoxTreeItem =
new CheckBoxTreeItem<String>("Stuff" + (i+1));
rootItem.getChildren().add(checkBoxTreeItem);
}
tree.setRoot(rootItem);
tree.setShowRoot(true);
// Create a custom menu item
CustomMenuItem customMenuItem = new CustomMenuItem(tree);
customMenuItem.setHideOnClick(false);
// Create the menu button
MenuButton mb = new MenuButton("Stuffs");
mb.getItems().add(customMenuItem);
And the output
Note: It is important to set the hideOnClickProperty to true, to avoid closing when the user clicks in the tree, which can be even done in the contructor, so you can shorten the initialization to:
CustomMenuItem customMenuItem = new CustomMenuItem(tree, false);
If you want to remove the hover glow, you can add the following CSS class:
.menu-item {
-fx-padding: 0;
}

Saving items added to a TableView via AddButton?

I'm totally new in Java and Im just trying out different little things. In the following code, I've set up a ListView into which I'm able to add new items via AddButton.
Now I'm wondering how to save those manually added items in my program so that next time Im running the code, not only the default items 1-5 within the code, but also the items I've manually added are shown in my table? I think I need to build some external library in which the manually added items are saved and be loaded every time I run the code again?
Also how can I enable marking and deleting multiple items with a single button click on delete?
And is there a another more detailed way to wright this code selectedProducts.forEach(allProducts:: remove); to see the background of whats happening here?
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
//BAUSTEINE - Eingabefeld:
TextField nameInput = new TextField();
nameInput.setMinWidth(100);
nameInput.setPromptText("Name");
TextField priceInput = new TextField();
priceInput.setMinWidth(100);
priceInput.setPromptText("Price");
TextField quantityInput = new TextField();
quantityInput.setMinWidth(100);
quantityInput.setPromptText("Quantity");
//BAUSTEINE - Tabelle:
TableColumn<Product, String> nameSpalte = new TableColumn<>();
nameSpalte.setText("Name");
nameSpalte.setMinWidth(200);
nameSpalte.setCellValueFactory(new PropertyValueFactory<>("Name"));
TableColumn<Product, Double> priceSpalte = new TableColumn<>();
priceSpalte.setText("Price");
priceSpalte.setMinWidth(200);
priceSpalte.setCellValueFactory(new PropertyValueFactory<>("price"));
TableColumn<Product, String> quantitySpalte = new TableColumn<>();
quantitySpalte.setText("Quantity");
quantitySpalte.setMinWidth(200);
quantitySpalte.setCellValueFactory(new PropertyValueFactory<>("quantity"));
TableView<Product> tabelle = new TableView<Product>();
tabelle.getColumns().addAll(nameSpalte, priceSpalte, quantitySpalte);
tabelle.setItems(getProduct());
//BAUSTEINE - Buttons:
Button addButton = new Button("Add");
addButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
Product product = new Product();
product.setName(nameInput.getText());
product.setPrice(Double.parseDouble(priceInput.getText()));
product.setQuantity(Integer.parseInt(quantityInput.getText()));
tabelle.getItems().addAll(product);
nameInput.clear();
priceInput.clear();
quantityInput.clear();
}
});
Button deleteButton = new Button("Delete");
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
ObservableList<Product> allProducts = tabelle.getItems();
ObservableList<Product> selectedProducts = tabelle.getSelectionModel().getSelectedItems();
selectedProducts.forEach(allProducts:: remove);
}
});
//LAYOUT:
HBox hBox = new HBox();
hBox.setPadding(new Insets(10,10,10,10));
hBox.setSpacing(10);
hBox.getChildren().addAll(nameInput, priceInput, quantityInput, addButton, deleteButton);
VBox vBox = new VBox();
vBox.getChildren().addAll(tabelle, hBox);
//EIGENSCHAFTEN DER SCENE:
Scene scene = new Scene(vBox);
//EIGENSCHAFTEN DER STAGE:
stage.setScene(scene);
//PROGRAMMSTART:
stage.show();
}
public ObservableList<Product> getProduct() {
ObservableList<Product> products = FXCollections.observableArrayList();
products.add(new Product("Item 1", 859.00, 20));
products.add(new Product("Item 2", 2.49, 198));
products.add(new Product("Item 3", 99.00, 74));
products.add(new Product("Item 4", 19.99, 12));
products.add(new Product("Item 5", 1.49, 856));
return products;
}
}
Is probably too broad a question for this forum. You need to decide
on how you want the products represented in a persistent format. It
could be in a flat file, in a text format you define (in which case
you would just use standard java.io classes to read and write
them), you could use Java serialization (again using standard
java.io; note that this is not very popular these days and, while
it's easy to get it working, it can be tricky to get it to work
well). You could use a standard format such as JSON or XML, and use
a library (e.g. Jackson or Google GSON) to marshal/unmarshal your
products to this format. Or you could use a relational database and
JDBC or JPA to read/write to the database. (Once you've decided how you want them represented, try an implementation and post specific questions if you are stuck.)
Use tabelle.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Your current code is basically equivalent to
for (Product p : selectedProducts) {
allProducts.remove(p);
}
Note that this is a little fragile, because removing an item from the list may result in resetting the selected items (depending on the implementation of the selection model, etc), in which case bad things will happen when you try to iterate through a list that is changing. It's probably better to copy the selected items to a new list:
List<Product> selectedItems = new ArrayList<>(tabelle.getSelctionModel().getSelectedItems());
for (Product p : selectedItems) {
allProducts.remove(p);
}
and note that there's also this:
List<Product> selectedItems = new ArrayList<>(tabelle.getSelctionModel().getSelectedItems());
allProducts.removeAll(selectedItems);

How can I get a Button's text in JavaFX if the Button is being read as a Node? Looping through Group/VBox of Buttons. Returns it as Nodes

I'm learning JavaFX and this is just a small programming question.
I have 3 buttons in a VBox. And I want to apply the same 3 effects on all buttons after I put them in the Vbox. But when I use a for loop and getChildren() on the VBox, they are returned as 'Nodes'. I can't use the Button.getText() to find out the text of the button.
Is there a way I can getText of a Node? Or maybe convert the current Node to a Button and get the text that way?
VBox vbox = new VBox();
Button option1 = new Button("Single Player");
Button option2 = new Button("Network Player");
Button option3 = new Button("View Rules");
vbox.getChildren().add(option1);
vbox.getChildren().add(option2);
vbox.getChildren().add(option3);
for (final Node button : vbox.getChildren()) {
button.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
button.setEffect(addEffect(Color.web("#53CFA6"), .8, 10));
}
});
button.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
button.setEffect(addEffect(Color.web("#FF6800"), .8, 10));
}
});
button.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
button.setEffect(addEffect(Color.web("#E62800"), .8, 10));
//Need to use button.getText()
//Button button; button.getText() works
}
});
}
there is two options:
1. Convert types. Easy, but not safe.
If you sure you wouldn't add other children to this VBox you can just convert Node to Button:
for (Node node : vbox.getChildren()) {
if (node instanceof Button) {
final Button button = (Button) node;
// all your logic
}
2. Use Factory pattern. Best suites, IMHO.
introduce method createButton which will setup button as you need:
private Button createButton(String name) {
final Button button = new Button(name);
button.setOnMouseEntered(...);
button.setOnMouseExited(...);
button.setOnMouseClicked(...);
return button;
}
and you code will look next way:
Button option1 = createButton("Single Player");
Button option2 = createButton("Network Player");
Button option3 = createButton("View Rules");
vbox.getChildren().addAll(option1, option2, option3);
3. Introduce your own Button class. Better if you plan to extend buttons logic.
public void FancyButton extends Button {
public FancyButton(String name) {
super(name);
//handlers logic here
}
}
You can get text from button and assign it to a string variable by this code :-
String Val = ((Button)event.getSource()).getText();

Categories

Resources