Howto cast List items from VBox.getChildren() in JavaFX - javafx

I have a VBox in which many nodes of type Buttonare added.
private final VBox vbox = new VBox();
private final Button b1= new Button("1");
private final Button b2= new Button("2");
private final Button b3= new Button("3");
private final Button b4= new Button("4");
vbox.getChildren().addAll(b1,b2,b3,b4);
Is there a way to cast its child items to Button type.
I need something like this:
ObservableList<Button> children = (ObservableList<Button>) vbox.getChildren();

Yes this is possible, if you use the raw type.
ObservableList<Button> children = (ObservableList)vbox.getChildren();
Note however, that this can easily lead to ClassCastExceptions at runtime, if the types are incorrect or the child list hardcodes the parameter type for a parameter that depends on the type parameter.

Related

JavaFX: getChildren().addAll() argument not applicable

I have a basic question for JavaFX but coudn't figure it out. For HBox, When I'm using getChildren().addAll() for Label and ImageView, I get the following message:
The method addAll(int, Collection<? extends Node>) in the type List<Node> is not applicable for the argument (Label, ImageView[])
I'm not sure what's the issue. I can use normally if its (TextField, ImageView[]), but it doesn't work for (Label, ImageView[]).
This is my simplified code:
ImageView[] imagesRow = new ImageView[2];
Image[] img = new Image[2];
String title = "Result";
img[0] = new Image("sample1.png", 60, 35, true, true);
img[1] = new Image("sample2.png", 60, 35, true, true);
imagesRow[0] = new ImageView();
imagesRow[1] = new ImageView();
imagesRow[0].setImage (img[0]);
imagesRow[1].setImage (img[1]);
Label label = new Label();
label.setText(title + ": ");
// Create horizontal box
HBox box = new HBox();
box.setPadding(new Insets(20, 5 , 2, 50));
box.getChildren().addAll(label, imagesRow); // issue here
May I seek the reason and what should I do instead to align label and image horizontally?
Thanks in advance.
A Collection needs to be of one type (or inheriting from a common parent somewhere in the heirarchy).
A Label is a type of Node and therefore anything else you try to pass as a part of the Collection parameter must also be a Node. An array is obviously not.
In your case, you would need to use two calls to populate the children of the HBox:
box.getChildren().add(label);
box.getChildren().addAll(imagesRow);
The reason you can call addAll(imagesRow) without a problem is because with only the one argument, you're only passing in one Collection, an array.
By calling addAll(label, imagesRow), you're telling Java that you're passing a Collection of one type, but you actually passed it a Node and an array.

Linking combobox in JavaFx

I have a interface with three combobox. Each combobox shows an attribute of an object and is sorted either alphabetical order or numerical order depending the case. When I select a item (atribute) from a combobox the other two shall select it's item (atribute) corresponding to the object.
I can't find documentation about it and don't have any clue about how to do it. I find information about nested combobox only but this is not the case.
I hope you understand.
In this example I've added a listener to one of the combo boxes, which "listens" for a change to the combo boxes selected value. Upon selecting a value within that combo box, the second combo box adjusts itself to have the corresponding value. You can take this same logic and apply it 3 ways by adding a listener to each combo box. Let me know if you have any questions!
ComboBox<String> combo = new ComboBox<String>();
combo.getItems().add("1");
combo.getItems().add("2");
combo.getItems().add("3");
combo.getSelectionModel().select(0); // value index to select
ComboBox<String> combo2 = new ComboBox<String>();
combo2.getItems().add("10");
combo2.getItems().add("20");
combo2.getItems().add("30");
combo2.getSelectionModel().select(0);
combo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue ov, String oldVal, String newVal) {
if (newVal.equals("1"))
if (combo2.getSelectionModel().getSelectedIndex() != 0)
combo2.getSelectionModel().select(0);
if (newVal.equals("2"))
if (combo2.getSelectionModel().getSelectedIndex() != 1)
combo2.getSelectionModel().select(1);
if (newVal.equals("3"))
if (combo2.getSelectionModel().getSelectedIndex() != 2)
combo2.getSelectionModel().select(2);
}
});

Access objects inside a dinamically created HBox

In the controller of my view, I created a list of HBoxes for the input of different values, each hbox consists of a textfield with an index number and two text boxes with information I want to retrieve. This is how I dynamically create each HBox.
void addRowToList() {
HBox hb = new HBox(50);
Text num = new Text(Integer.toString(numEdges + 1));
hb.getChildren().add(num);
TextField sep = new TextField();
makeNumeric(sep);
hb.getChildren().add(sep);
TextField area = new TextField();
makeNumeric(area);
hb.getChildren().add(area);
rows.add(hb);
}
After this, there is a point in which I need the information from those textBoxes in order to continue the execution of my program, my question is what is the method should I follow to access these since they don't have any given id? Thanks in advance.

Javafx ComboBox list contents in sorted order

I'm trying to have a ComboBox list the contents in sorted order. I've come up with one solution, but it still has some issues.
final ObservableList<String> oal = FXCollections.observableArrayList();
final SimpleListProperty<String> slp = new SimpleListProperty<String>(oal);
final SortedList<String> sl = new SortedList<String>(slp, (string1, string2) -> {
return string1.compareTo(string2);
});
final ComboBox<String> comboBox = new ComboBox<String>();
comboBox.setItems(sl);
I can add values to OAL or SLP.
oal.addAll("cccc", "aaaa", "bbbb");
slp.addAll("ffff", "dddd", "eeee");
But if I try to add values to SL, it fails.
sl.addAll("iiii", "hhhh", "gggg");
Exception in thread "main" java.lang.UnsupportedOperationException
So of course any attempts to add values to comboBox also fail. Does anybody know a way to fix this, or is there a totally different approach to sorting the contents of the ComboBox?
I appreciate any help here.
I'm using Java 8u5.
Can't you just add items to the underlying list instead of the sorted list?
final ObservableList<String> comboBoxItems = FXCollections.observableArrayList();
final ComboBox<String> comboBox = new ComboBox<String>();
comboBox.setItems(new SortedList<String>(comboBoxItems, Collator.getInstance()));
And then just always add items to comboBoxItems.
I'm adding this as an answer as I don't have enough stackoverflow reputation to comment.
Be aware that there is currently (Java 8u92 and probably before) a bug JDK-8087838 that causes extra unwanted Combobox OnAction events to fire when adding items to an editable combobox when a SortedList is used instead of an ObservableList. This bug makes it difficult to properly code for the combobox events, so I suggest not using a SortedList until the bug is fixed. See also this stackoverflow question.

JavaFX architecture in building dynamic "rows"

I have an application that I am building that has a table in it, I'm not using a tableview to build this table because I need each row to be able to expand similar to an accordion. I was able to achieve what I need by using a timeline and looping through the data and building each row (its kind of crude right now since I'm still working with dummy data eventually it will be a list iterator and not just a for loop) but I'm not happy with how its done. There are a lot of default values that will never change so I don't really need to set them in my worker class every time, I decided to just add them to the object class that I put together. So basically, at a high level it looks something like this:
for (int i = 0; i < 30; i++) {
RowBuilder builder = new RowBuilder(tableBox, i);
try {
builder.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I'm passing it the parent which is a VBox - tableBox, then I'm passing the count for later use.
Inside the RowBuilder I'm getting a new instance of the object DashboardRow which has all the defaults set in it, then I'm setting the data for each row and returning the DashboardRow.
Here is an example of a getter setting values in the DashboardRow
public HBox getMainRow() {
mainRow.setAlignment(Pos.CENTER_LEFT);
mainRow.setPrefHeight(60);
mainRow.setMinHeight(60);
mainRow.setMaxHeight(60);
mainRow.setPrefWidth(-1);
mainRow.setStyle("-fx-background-color:#FFFFFF;");
return mainRow;
}
Inside the DashboardRow class I have a ton of new objects being created for every element I need in the row. There are 21 for each row, mostly VBox, HBox and StackPane to build the actual row, the rest are just labels and buttons.
This is what is looks like so far. Opened and closed states.
Is there a better way to dynamically build things like this in javafx? I'm basically pulling data from a database and looping through that data to populate a row.
I can't comment but it may be an answer anyway. Why can't you use the setGraphic method of a custom table cell and put the accordion node in a table. setGraphic takes any kind of node.
It sounds simpler than what you're doing.
I just tried it out with the Oracle sample and it works great.
I added
Callback<TableColumn<Person, String>, TableCell<Person, String>> accCellFactory
= new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {
#Override
public TableCell call(TableColumn p) {
TitledPane t1 = new TitledPane("T1", new Button("B1"));
TitledPane t2 = new TitledPane("T2", new Button("B2"));
TitledPane t3 = new TitledPane("T3", new Button("B3"));
Accordion accordion = new Accordion();
accordion.getPanes().addAll(t1, t2, t3);
TableCell tc = new TableCell();
tc.setGraphic(accordion);
return tc;
}
};
and changed this line firstNameCol.setCellFactory(accCellFactory);
and I get
Of course you might want something other than buttons but I just copied the Accordion sample from the javadoc.

Resources