JavaFX nested controls, how to get selection? - javafx

I try to implement an application with JavaFX 8 where I have a ListView of GridPanes, where each GridPane consists of 2 other controls (ChoiceBoxes). The Gridpanes in the ListView are dynamically added by the user during runtime. What I like to achive is to add a listener to the ChoiceBox such that I know to which ListView item/index the selected choicebox belongs to if a user makes a choice.
My Problem is now that I cannot get the index of the ListView when the user selects an item of the choicebox, because the item (i.e. the Gridpane) in ListView is not (automatically) selected or focused in this case.
Can anybode help me with this?

Thanks for the comments, I got the solution now by looking for the parent of the choicebox (note that paneList is an ArrayList in which I stored the references to the GridPanes which where added by the user)
// define Listener for choiceBox
choiceBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
GridPane parent = (GridPane) choiceBox.getParent();
// keep track of selected choice
selectedChoice = newValue;
logger.debug("selected choice: {}", selectedChoice);
// keep also track of parent GridPane
selectedGridpane = paneList.indexOf(parent);
logger.debug("selected GridPane {}", paneList.indexOf(parent));
});

Related

Java FX looping through Anchor pane to get CheckBox name and if selected

I have an Anchorpane which will have up to 20+ check boxes on it. I want to write a loop to get the name of each check box and if it is selected.
I have this working code so far
import javafx.scene.layout.AnchorPane;
#FXML
private AnchorPane lootAnchorPane;
ObservableList<Node> children = lootAnchorPane.getChildren();
for (Node child : children) {
System.out.println(child.getId());
}
This prints the id's well enough but I am not able to use child.getText() or child.isSelected(). As far as i understand the Checkbox classes are returned. I think it has something to do with the #FXML annotation. But im not sure how to implement this inside a for loop?
The asker has indicated that this question has already been answered by the kind commenter Sedrick. To try and make it as clear as possible to anyone viewing this post afterwards, I am posting a formal answer with a code example.
To use CheckBox methods with Node objects you have to first make sure the Node is an instance of a CheckBox. Use if (child instanceOf Node) to do so. If they are, it is safe to cast them to CheckBox type, and you can then use CheckBox methods with them.
ObservableList<Node> children = lootAnchorPane.getChildren();
for (Node child : children) {
// check if Node is an instance of CheckBox.
if (child instanceOf CheckBox) {
// Cast child Node to CheckBox
CheckBox checkBox = (CheckBox) child;
// --- do stuff with the CheckBox object.
}
}

In JavaFx, how to control focus of a custom control?

Suppose a JavaFX CustomControl node that contains, say, two TextFields.
If any of these TextFields has the focus, then CustomControl.isFocused() should return true. If none of them has focus, then CustomControl.isFocused() should return false.
How do I do that?
As your CustomControl uses composition, you can delegate to the focus properties of each TextField. Given two instances,
private final TextField tf1 = new TextField("One");
private final TextField tf2 = new TextField("Two");
The implementation of an instance method isFocused() is then straightforward:
private boolean isFocused() {
return tf1.isFocused() | tf2.isFocused();
}
Add focus listeners as shown here to see the effect.
tf1.focusedProperty().addListener((Observable o) -> {
System.out.println(isFocused());
});
tf2.focusedProperty().addListener((Observable o) -> {
System.out.println(isFocused());
});
This can't be done. The whole problem is that isFocused() is final in Node.
It seems you wanted to override isFocused() in CustomControl, but that is not possible for a final method and it would violate the notion of a single component having focus. As CustomControl is a composite, you'll need to manage focus internally. You may want to use a custom FocusModel as seen in ListView.
Try one line solution:
public BooleanBinding aggregatedFocusProperty() {
return Bindings.or(field1.focusedProperty(), field2.focusedProperty());
}
Now on a client side you may listen this aggregated focus property.

ComboBox selected value not getting translated

My app should have several languages. English is by default. Problem is that if user will switch to different language, everything will be translated except for ComboBox selected value. This is how it looks:
Code behind ComboBox is:
ObservableList<Currency> currencyItem= CurrencyDA.getCurrencies();
currenciesComboBox.setItems(currencyItem);
Callback<ListView<Currency>, ListCell<Currency>> currencyFactory = lv -> new ListCell<Currency>(){
#Override
protected void updateItem(Currency currency, boolean empty){
super.updateItem(currency, empty);
setText(empty ? "" : interfaceBundle.getString("currency_"+currency.getName()));
}
};
currenciesComboBox.setCellFactory(currencyFactory);
currenciesComboBox.setButtonCell(currencyFactory.call(null));
currenciesComboBox.getSelectionModel().selectFirst();
How can I get selected value refreshed?
From the doc
As the ComboBox internally renders content with a ListView, API exists in the ComboBox class to allow for a custom cell factory to be set. For more information on cell factories, refer to the Cell and ListCell classes. It is important to note that if a cell factory is set on a ComboBox, cells will only be used in the ListView that shows when the ComboBox is clicked. If you also want to customize the rendering of the 'button' area of the ComboBox, you can set a custom ListCell instance in the button cell property. One way of doing this is with the following code :
//(note the use of setButtonCell):
Callback<ListView<String>, ListCell<String>> cellFactory = ...;
ComboBox comboBox = new ComboBox();
comboBox.setItems(items);
comboBox.setButtonCell(cellFactory.call(null));
comboBox.setCellFactory(cellFactory);
So the only thing you have to add is :
currenciesComboBox.setButtonCell(currencyFactory.call(null));

How to skip DRAG_DETECTED Events from TableHeaderRow (resizing TableColumns)

In order to use a TableView (with resizable columns) as drag source,
I have attached an onDragDetected handler on that TableView with the effect, that resizing TableColumns does not work anymore: If the user clicks into the TableHeaderRow for dragging the column separators, these mouse events are consumed by my handler too.
The handler is attached to the whole TableView and I do not see a way to distinguish between events from TableRows and events from the TableHeaderRow.
Attaching the handler to the data-rows only is not appropriate in my case, since I need multiline selection (and do not want to have dependencies from the RowFactory to the application data model).
Any suggestions?
best Hans
I found the solution myself: I had to look up the TableHeaderRow instance with the lookup-method, and discard the DRAG_DETECTED event there.
Pane header = (Pane) mainTableView.lookup("TableHeaderRow");
header.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
System.out.println("ignoring drag operation from table header.");
event.consume();
}
});
After that, resising of table columns works. Maybe there is something wrong with my drag+drop event handling that initially caused the problem!? Somebody voted down without comment...
The solution by Hans does work, but only after the window is shown. I added a window.setOnShown((WindowEvent e) listener and then I was able to do the lookup and header.setOnDragDetected.
Here is how I added it:
window.setOnShown((WindowEvent e) -> {
Pane header = (Pane) mainTableView.lookup("TableHeaderRow");
....
});
Otherwise, lookup returns null.

JavaFX combobox displays wrong number of items when updating Observable list

I have a combobox whose items can change. When changing the items of said combobox to have less items then previously, the combobox still displays the same amount of item fields, the 'extra' fields being blank.
Like so: http://imgur.com/W03NOgo,rGjtNev#1
Here is the code I use to change the combobox.
#FXML private ComboBox<Task> taskComboBox;
private ObservableList<TaskDTO> tasks = FXCollections.observableArrayList();
public Foo() {
taskComboBox.setItems(tasks);
}
#FXML
private void loadTaskComboBox(int i) {
tasks.clear();
tasks.addAll(getTasks(i));
}
Any help would be greatly appreciated.
ComboBox API:
By default, when the popup list is showing, the maximum number of rows
visible is 10, but this can be changed by modifying the
visibleRowCount property. If the number of items in the ComboBox is
less than the value of visibleRowCount, then the items size will be
used instead so that the popup list is not exceedingly long.
But on the other hand, if the number of items is shrinking, the ListView (popup content) will not shrink. But you can adjust the visibleRowCountProperty to adjust the number of visible items.

Resources