I want to add two button in action TableColumn, i already read this How to add button in JavaFX table view and this Add a button to a cells in a TableView (JAVAFX) but both of them use one button in setGraphic, so when i try to use :
actionFld.setCellFactory(param -> new TableCell<Patient, Patient>() {
private final JFXButton editButton = new JFXButton("edit");
private final JFXButton deleteButton = new JFXButton("delete");
#Override
protected void updateItem(Patient patient, boolean empty) {
super.updateItem(patient, empty);
if (patient == null) {
setGraphic(null);
return;
}
deleteButton.setOnAction(event -> {
Patient getPatient = getTableView().getItems().get(getIndex());
System.out.println(getPatient.getNom() + " " + getPatient.getPrenom());
});
editButton.setOnAction(event -> {
Patient getPatient = getTableView().getItems().get(getIndex());
System.out.println(getPatient.getNom() + " " + getPatient.getPrenom());
});
setGraphic(deleteButton);//<<<---------------add button 1
setGraphic(editButton);//<<------------------add button 2
}
});
it show me just one button :
How can i solve this problem?
You can use HBox to add your component one beside the other for example :
HBox pane = new HBox(deleteButton, editButton);
setGraphic(pane);
result:
If you have another way, i will be happy for it!
Related
I am fairly new in JavaFX. I have a table with multiple columns and two buttons (btnBuilding , btnBSearch) outside the table. In the table, I have a column colAction where I want to have some buttons based on the button clicked outside the table. Suppose if I click btnBuilding I want to have 2 button Save and Refresh in my colAction column and Whenever I click btnBSearch I want to have 2 button Edit and Add in my colAction column. Inside the initialize() I tried like below
colAction.setCellFactory(col -> {
Button SaveButton = new Button("Save");
Button AddButton = new Button("Add");
Button RefreshButton = new Button("Refresh");
Button EditButton = new Button("Edit");
HBox hbox = new HBox(5);
if(btnBSearch.isFocused())
hbox.getChildren().addAll(AddButton,EditButton);
else if(btnBuilding.isFocused())
hbox.getChildren().addAll(SaveButton,RefreshButton);
TableCell<ModelBrBuilding, ModelBrBuilding> cell = new TableCell<ModelBrBuilding, ModelBrBuilding>() {
#Override
//Updating with the number of row
public void updateItem(ModelBrBuilding building, boolean empty) {
super.updateItem(building, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(hbox);
}
}
};
EditButton.setOnAction((ActionEvent event)->{
});
RefreshButton.setOnAction(event->{
});
SaveButton.setOnAction((ActionEvent event) -> {
});
AddButton.setOnAction(event -> {
});
return cell ;
});
But the problem is whatever button I click I am always getting Add and Edit in my action column. How can I add different button in my column based on the button (resides outside the table) I click?
The cellFactory runs only once for each cell. You need to make sure the cell is updated the button outside of the table is clicked.
You could do this by creating a property that contains a factory for the graphics and listen to it.
public interface GraphicFactory<T> {
Node createGraphic();
void updateGraphic(Node graphic, T item);
}
public class ReplacableGraphicTableCell<S, T> extends TableCell<S, T> {
private final ChangeListener<GraphicFactory<T>> factoryListener = (o, oldValue, newValue) -> {
if (newValue == null || isEmpty()) {
setGraphic(null);
} else {
Node n = newValue.createGraphic();
newValue.updateGraphic(n, getItem());
setGraphic(n);
}
};
private final ObservableValue<GraphicFactory<T>> factory;
private ReplacableGraphicTableCell(ObservableValue<GraphicFactory<T>> factory) {
this.factory = factory;
factory.addListener(factoryListener);
}
public static <E, F> Callback<TableColumn<E, F>, TableCell<E, F>> forTableColumn(ObservableValue<GraphicFactory<F>> factory) {
if (factory == null) {
throw new IllegalArgumentException();
}
return column -> new ReplacableGraphicTableCell(factory);
}
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
GraphicFactory<T> fact = factory.getValue();
if (fact == null) {
setGraphic(null);
} else {
Node graphic = getGraphic();
if (graphic == null) {
graphic = fact.createGraphic();
setGraphic(graphic);
}
fact.updateGraphic(graphic, item);
}
}
}
}
final ObjectProperty<GraphicFactory<Item>> graphicFactory = new SimpleObjectProperty<>();
TableColumn<Item, Item> column = new TableColumn<>();
column.setCellValueFactory(cd -> new SimpleObjectProperty<>(cd.getValue()));
column.setCellFactory(ReplacableGraphicTableCell.forTableColumn(graphicFactory));
ToggleGroup tg = new ToggleGroup();
tg.selectedToggleProperty().addListener((o, oldValue, newValue) -> {
GraphicFactory<Item> factory = null;
if (newValue != null) {
factory = (GraphicFactory<Item>) newValue.getUserData();
}
graphicFactory.set(factory);
});
RadioButton rb = new RadioButton("Add/Edit");
rb.setUserData(new GraphicFactory<Item>() {
#Override
public Node createGraphic() {
Button add = new Button("Add");
Button edit = new Button("Edit");
HBox hbox = new HBox(add, edit);
add.setOnAction(evt -> {
System.out.println("Add " + hbox.getUserData());
});
edit.setOnAction(evt -> {
System.out.println("Edit " + hbox.getUserData());
});
return hbox;
}
#Override
public void updateGraphic(Node graphic, Item item) {
graphic.setUserData(item);
}
});
rb.setToggleGroup(tg);
RadioButton rb2 = new RadioButton("Save/Refresh");
rb2.setUserData(new GraphicFactory<Item>() {
#Override
public Node createGraphic() {
Button save = new Button("Save");
Button refresh = new Button("Refresh");
HBox hbox = new HBox(save, refresh);
save.setOnAction(evt -> {
System.out.println("Save " + hbox.getUserData());
});
refresh.setOnAction(evt -> {
System.out.println("Refresh " + hbox.getUserData());
});
return hbox;
}
#Override
public void updateGraphic(Node graphic, Item item) {
graphic.setUserData(item);
}
});
rb2.setToggleGroup(tg);
It will not work this way. To begin with, you need to process the btnBuilding and btnBSearch buttons. Which of the buttons is pressed must reflect in the table you are using. For this purpose, one feature can be created propert to reflect which of the two buttons is pressed.
BooleanProperty showSearch = new SimpleBooleanProperty(false);
...
btnBuilding.setOnAction(e -> showSearch.setValue(false));
btnBSearch.setOnAction(e -> showSearch.setValue(true));
Then, you link the colAction column to the value of the property.
colAction.setCellValueFactory(cdf -> showSearch);
In this situation, you can create CellFactory to create the dynamic content cell
colAction.setCellFactory(col -> {
return new TableCell<String, Boolean>() {
Button SaveButton = new Button("Save");
Button AddButton = new Button("Add");
Button RefreshButton = new Button("Refresh");
Button EditButton = new Button("Edit");
HBox hboxBuilding = new HBox(5);
HBox hboxSearch = new HBox(5);
{
hboxBuilding.getChildren().addAll(AddButton,EditButton);
hboxSearch.getChildren().addAll(SaveButton,RefreshButton);
}
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
}
else {
setGraphic(item ? hboxBuilding : hboxSearch);
}
}
};
});
I am new to programming, using JavaFX at the moment for a personal organization tool. I have showed here an arraylist of buttons(called books) and stages(called bookStages), a VBox called addBook, and an Int called bookButtonCount set to 0.
addBook.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
addBooks.getChildren().add(books.get(bookButtonCount));
books.get(bookButtonCount).setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
bookStages.get(bookButtonCount).show();
System.out.println(bookButtonCount);
}
});
bookButtonCount++;
}
});
The first button adds a button from the "books" arraylist to the VBox. The button from the vbox is supposed to open a stage from the stage arraylist. You should be able to fire the button multiple times, each time adding a new button to the vbox and setting that button to open its own stage. Though it seems that using bookButtonCount as a reference will not work because each time you press a button from the books arraylist in the vbox, it checks for the current value of bookButtonCount.(Which changes as more buttons are added) and opens the wrong stage.
Is there any way to have the action for the button be saved with the value of bookButtonCount at the time it is set only?
If not, how should I set this up?
Here is some more bits of code that may be useful:
ArrayList<Stage> bookStages = new ArrayList();
ArrayList<Button> books = new ArrayList();
for (int i=0;i<10;i++){
books.add(new Button("Book " + (i+1)));
bookStages.add(new Stage());
bookStages.get(i).setTitle("Book " + (i+1));
}
Just register the handler when you create the button and stage:
ArrayList<Stage> bookStages = new ArrayList();
ArrayList<Button> books = new ArrayList();
for (int i=0;i<10;i++){
Button button = new Button("Book " + (i+1));
books.add(button);
Stage stage = new Stage();
bookStages.add(stage);
stage.setTitle("Book " + (i+1));
button.setOnAction(e -> stage.show());
}
and
addBook.setOnAction(e -> {
addBooks.getChildren().add(books.get(bookButtonCount));
bookButtonCount++ ;
});
I have a simple login panel that I wrote using Swing and now I have to redo everything with JavaFX, but I don't know how to convert the ActionListeners/MouseListeners.
Whenever the "Neu-Anmeldung" checkbox is checked/unchecked, the values true/false should be seen in the Eclipse console.
My Swing code for this purpose:
// ...
this.jBoxNeuAnmeldung.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (LoginFrame.this.jBoxNeuAnmeldung.isSelected())
neuAnmeldung = true;
else
neuAnmeldung = false;
System.out
.println("Neu-Anmeldung Checkbox angekreutzt? " + neuAnmeldung);
}
});
// ...
How do I do the same thing with JavaFX?
...
checkBox.setOnAction((event) -> {
neuAnmeldung = checkBox.isSelected();
System.out.println("Neu-Anmeldung Checkbox angekreutzt? "
+ neuAnmeldung);
});
replace checkBox by check box name, e.g.
final CheckBox jBoxNeuAnmeldung = new CheckBox();
...
jBoxNeuAnmeldung.setOnAction((event) -> {
neuAnmeldung = jBoxNeuAnmeldung.isSelected();
System.out.println("Neu-Anmeldung Checkbox angekreutzt? "
+ neuAnmeldung);
});
(in standard Java 8 you can also omit final in CheckBox when used in labmda expression).
By adding a ChangeListener to the selected property
checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> System.out.println("Neu-Anmeldung Checkbox angekreutzt? " + newValue));
#FXML
public CheckBox checkBoxNeuAnmeldung;
#FXML
public void handleCheckBoxNeuAnmeldungAction(ActionEvent event) {
if (checkBoxNeuAnmeldung.isSelected()) {
neuAnmeldung = true;
} else
neuAnmeldung = false;
System.out.println("Neu-Anmeldung Checkbox angekreutzt? " + neuAnmeldung);
}
I managed to implement a simpler method using ActionEvent and connected it tp my FXML file.
I have a javafx checkbox tree. I need to select the checkbox when the tree item is clicked. I have added a listener for the selection property of the tree view. But the listener gets fired only when the tree item is clicked. The above listener is not fired when the checkbox is clicked.
Required: A listener that fires when a tree item or checkbox is clicked in the treeview.
Code:
String memberArray = {"subChild1", "subChild2", "childSub1"}
Group groupRoot = new Group();
Scene scene = new Scene(groupRoot, Color.ALICEBLUE);
HBox hBox = new HBox();
hBox.setMaxWidth(fxPanel.getWidth());
final Label royalLabel = new Label("Select a item");
TreeSet<String> prefixMember = new TreeSet<String>();
String tmpName = null;
LinkedHashSet<CheckBoxTreeItem<String>> treeItems = new LinkedHashSet<CheckBoxTreeItem<String>>();
LinkedHashSet<CheckBoxTreeItem<String>> treeSubItems = new LinkedHashSet<CheckBoxTreeItem<String>>();
for (String item : memberArray) {
if (!item.isEmpty()) {
tmpName = item.substring(0, 3);
prefixMember.add(tmpName);
}
}
// Create and empty TreeView
TreeView<String> duckTree = new TreeView<String>();
// Create TreeItems for the Hierarchy of the TreeView
CheckBoxTreeItem<String> root = new CheckBoxTreeItem<String>("Parent");
CheckBoxTreeItem<String> lm1 = new CheckBoxTreeItem<String>("Child1");
CheckBoxTreeItem<String> lm2 = new CheckBoxTreeItem<String>("Child2");
for (String item : prefixMember) {
CheckBoxTreeItem<String> treeItem = new CheckBoxTreeItem<String>(item.toString());
for (String subItem : memberArray) {
if (!subItem.isEmpty() && subItem.substring(0, 3).equals(item)) {
CheckBoxTreeItem<String> treeSubItem = new CheckBoxTreeItem<String>(
subItem.toString());
treeSubItems.add(treeSubItem);
}
}
treeItems.add(treeItem);
treeItem.getChildren().addAll(treeSubItems);
treeSubItems.clear();
}
root.getChildren().addAll(treeItems);
treeItems.clear();
// Create a TreeView using the root TreeItem
TreeView<String> royalTree = new TreeView<String>(root);
royalTree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
// Set a ChangeListener to handle events that occur with a Treeitem
// is selected
royalTree.getSelectionModel().selectedItemProperty()
.addListener(new ChangeListener<TreeItem<String>>() {
public void changed(
ObservableValue<? extends TreeItem<String>> observableValue,
TreeItem<String> oldItem, TreeItem<String> newItem) {
// Gets fired only on selection of tree item
// Need to get fired on selection of check box too
// Select the respective checkbox on selection of tree item
}
});
hBox.getChildren().add(royalTree);
groupRoot.getChildren().add(hBox);
fxPanel.setScene(scene);
You could just add an EventHandler to your root item in the tree:
rootItem.addEventHandler(CheckBoxTreeItem.checkBoxSelectionChangedEvent(), new EventHandler<TreeModificationEvent<Object>>() {
#Override
public void handle(TreeModificationEvent<Object> event) {
// Your code here.
}
});
i had the same problem and searched looong time. Sadly there is not offical documentation for this from oracle.
The answer is to set the CellFactory and call the getSelectedStateCallback().call(this.getTreeItem());
for your treeItem in the updateItem:
// set cellFactory
royalTree.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> p) {
// return new CheckBoxTreeCell, you also can make a new class with this
return new CheckBoxTreeCell<String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// call the selectedStat Callback for treeitem
ObservableValue<Boolean> selectedState = getSelectedStateCallback().call(this.getTreeItem());
if (selectedState != null) {
// do something here
}
}
}
};
}
});
i have tested this in fx 8, but it should also work in fx 2.2
happy coding,
kalasch
Yes, adding an event handler to the tree item works. Here is some example code (Java 8) with a TreeView with items as CheckBoxTreeItem:
CheckBoxTreeItem<Path> rootItem = new CheckBoxTreeItem<>(rootDirPath);
rootItem.addEventHandler(
CheckBoxTreeItem.<Path>checkBoxSelectionChangedEvent(),
(TreeModificationEvent<Path> e) -> {
CheckBoxTreeItem<Path> item = e.getTreeItem();
if (item.isSelected() || item.isIndeterminate()) {
System.out.println("Some items are checked");
}
else {
System.out.println("Some items are unchecked");
}
});
TreeView<Path> tree = new TreeView<>(rootItem);
tree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Do you require an event for each selection immediately? If not you can create an arraylist of all your checkboxtreeitems and iterate through that to check for selected or not selected when you need it.
I have one OK button(push button) created.
Based on user input i want to dynamically create 1 to 10 SWT buttons(check box).
How to create it?
If OK button is clicked, how to display which are all check box button has been selected?
Please find below snippet I am trying with:
Set<String> Groups = getData(Contents);
for(String group : contentGroups) {
contentButton = new Button(fComposite, SWT.CHECK);
// is this right way to create dynamic buttons?
contentButton.setText(group);
}
okButton = new Button(lowComposite, SWT.PUSH);
okButton.addSelectionListener(new SelectionListener(){
#Override
public void widgetSelected(SelectionEvent e){
//Here how to get the selection status of contentButtons?
}
}
This will print out the selection state of the buttons:
Set<String> Groups = getData(Contents);
final List<Button> buttons = new ArrayList<Button>();
for(String group : contentGroups)
{
Button newButton = new Button(fComposite, SWT.CHECK);
newButton.setText(group);
// save the button
buttons.add(newButton);
}
Button okButton = new Button(lowComposite, SWT.PUSH);
okButton.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event e)
{
// iterate over saved buttons
for(Button button : buttons)
{
System.out.println(button.getText() + ": " + button.getSelection());
}
}
}