Javafx ThreeView Manual Settings Selected - javafx

I have a view, using TreeView as a tree view display. I want to manually set a child node as the selected state. How should I set it?

TreeView selections work basically the same as ListView selections, as long as you ignore indices. Just pass the TreeItem you want to select to the select method of the selection model:
#Override
public void start(Stage primaryStage) throws Exception {
TreeItem<String> c1 = new TreeItem<>("child 1");
TreeItem<String> c2 = new TreeItem<>("child 2");
TreeItem<String> root = new TreeItem<>("root");
root.getChildren().addAll(c1, c2);
TreeView<String> tv = new TreeView<>(root);
// select c2
tv.getSelectionModel().select(c2);
Scene scene = new Scene(tv);
primaryStage.setScene(scene);
primaryStage.show();
}

Related

JAVAFX How can I create a method for setting objects visible?

I am new to Java and JavaFX so sorry if this question seems a bit obvious but it is doing my head in. I have tried googling solutions but haven't been able to find anything so far.
Basically I am trying to re-use some code in Java FX to hide / show some objects when a button is pressed. Rather than copy / paste the whole code again, I want to put it in a method (or something similar) that gets called on different occasions.
So here is a simple code example that I hope explains what I am trying to do:
package src;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class example extends Application
{
#Override
public void start(Stage stage)
{
Button b1 = new Button();
b1.setText("Show Label 1 Only");
Button b2 = new Button();
b2.setText("Show Label 2 Only");
Button b3 = new Button();
b3.setText("Show Label 2 and 3");
Label l1 = new Label();
l1.setText("Label 1");
Label l2 = new Label();
l2.setText("Label 2");
Label l3 = new Label();
l3.setText("Label 3");
b1.setOnAction(e ->
{
l1.setVisible(true);
l2.setVisible(false);
l3.setVisible(false);
});
b2.setOnAction(e ->
{
l1.setVisible(false);
l2.setVisible(true);
l3.setVisible(false);
});
b3.setOnAction(e ->
{
l1.setVisible(false);
l2.setVisible(true);
l3.setVisible(true);
});
VBox root = new VBox();
root.setSpacing(10);
root.setAlignment(Pos.CENTER);
l1.setVisible(false);
l2.setVisible(false);
l3.setVisible(false);
root.getChildren().addAll(b1, b2, b3, l1, l2, l3);
Scene scene = new Scene(root, 200, 200);
stage.setScene(scene);
stage.setTitle("Example");
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
As you can see, the first 2 lines of the code for B2 and B3 are the same, so it would be nice if I could just put these lines in a method that gets called in both scenarios. This is in essence what i am trying to achieve.
Any guidance would be much appreciated. Like I said, I'm new to JAVA / JAVAFX so sorry if it seems like an obvious question.
One simple way is to make the labels instance variables and just to define a method taking a boolean for each one, indicating if it should be visible:
public class Example extends Application {
private Label l1;
private Label l2;
private Label l3;
private void labelVisibility(boolean l1Visible, boolean l2Visible, boolean l3Visible) {
l1.setVisible(l1Visible);
l2.setVisible(l2Visible);
l3.setVisible(l3Visible);
}
#Override
public void start(Stage stage) {
Button b1 = new Button();
b1.setText("Show Label 1 Only");
Button b2 = new Button();
b2.setText("Show Label 2 Only");
Button b3 = new Button();
b3.setText("Show Label 2 and 3");
l1 = new Label();
l1.setText("Label 1");
l2 = new Label();
l2.setText("Label 2");
l3 = new Label();
l3.setText("Label 3");
b1.setOnAction(e -> labelVisibility(true, false, false));
b2.setOnAction(e -> labelVisibility(false, true, false));
b3.setOnAction(e -> labelVisibility(false, true, true));
VBox root = new VBox();
root.setSpacing(10);
root.setAlignment(Pos.CENTER);
labelVisibility(false, false, false);
root.getChildren().addAll(b1, b2, b3, l1, l2, l3);
Scene scene = new Scene(root, 200, 200);
stage.setScene(scene);
stage.setTitle("Example");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you don't want to expand the scope of the labels (and want a bit more generality), your method can take a list of all the labels, and a list of the ones you want visible:
public class Example extends Application {
private void labelVisibility(List<Node> allNodes, Node... visibleNodes) {
List<Node> visibleNodeList = Arrays.asList(visibleNodes);
for (Node node : allNodes) {
node.setVisible(visibleNodeList.contains(node));
}
}
#Override
public void start(Stage stage) {
Button b1 = new Button();
b1.setText("Show Label 1 Only");
Button b2 = new Button();
b2.setText("Show Label 2 Only");
Button b3 = new Button();
b3.setText("Show Label 2 and 3");
Label l1 = new Label();
l1.setText("Label 1");
Label l2 = new Label();
l2.setText("Label 2");
Label l3 = new Label();
l3.setText("Label 3");
List<Node> allLabels = List.of(l1, l2, l3);
b1.setOnAction(e -> labelVisibility(allLabels, l1));
b2.setOnAction(e -> labelVisibility(allLabels, l2));
b3.setOnAction(e -> labelVisibility(allLabels, l2, l3));
VBox root = new VBox();
root.setSpacing(10);
root.setAlignment(Pos.CENTER);
labelVisibility(allLabels);
root.getChildren().addAll(b1, b2, b3, l1, l2, l3);
Scene scene = new Scene(root, 200, 200);
stage.setScene(scene);
stage.setTitle("Example");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Java FX - Controlling one combobox/choicebox using other combobox/choicebox

I want to change the combobox by selecting item from another combobox. Means, I want to control one combobox using other combobox. For example, if I have a combobox containing names and other containing countries, then if I select Mumbai from names then other combobox should automatically display India.
Please help me out a little bit to solve this problem. A piece of code will work for me to explain.
I think this is what you mean where the second combobox is dependent on what is chosen in the first
public class Main extends Application {
#Override
public void start(Stage stage) {
ComboBox comboBox2 = new ComboBox();
ComboBox comboBox = new ComboBox();
comboBox.getItems().addAll("Option 1", "Option 2", "Option 3");
comboBox.setOnAction(event -> {
comboBox2.getItems().clear();
for (int i = 0; i < 5; i++) {
comboBox2.getItems().add(comboBox.getValue().toString());
}
});
VBox vBox = new VBox();
vBox.getChildren().addAll(comboBox, comboBox2);
Scene scene = new Scene(vBox);
stage = new Stage();
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}

Allow clicks to go through application GUI

I have a JavaFx application that loads a transparent stage with some text on it.
I want any click on the application to be completely ignored and the background application (if any) to receive that click.
My code at this stage is as follows:
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.show();
layout.setMouseTransparent(true);
mainText.setMouseTransparent(true);
}
I was not able to achieve the requirement. setMouseTransparent() just prevented the text from triggering events, it still captured the mouse clicks.
Is it possible to achieve this in JavaFx ? Even if it is a per-OS solution.
A way of doing this action in Windows is through user32.dll and Java Native Access (JNA). We used GetWindowLong to get the current configuration of the window and SetWindowLong to update the bit field that is controlling the ability of the window be transparent to the mouse.
Following is a working example that demonstrates this functionality:
#Override
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.setTitle(sTitle);
primaryStage.show();
sUser32.EnumWindows(
(hWnd, data) -> {
final byte[] windowText = new byte[512];
sUser32.GetWindowTextA(hWnd, windowText, 512);
final String wText = Native.toString(windowText);
if (!wText.isEmpty() && wText.equals(sTitle)) {
final int initialStyle = com.sun.jna.platform.win32.User32.INSTANCE.GetWindowLong(hWnd, WinUser.GWL_EXSTYLE);
com.sun.jna.platform.win32.User32.INSTANCE.SetWindowLong(hWnd, WinUser.GWL_EXSTYLE, initialStyle | WinUser.WS_EX_TRANSPARENT );
return false;
}
return true;
}, null);
}

Set image on left side of dialog

I created this very simple example for JavaFX alert dialog for JavaFX8u40.
public class MainApp extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception
{
Button create = new Button("Create Alert");
create.setTooltip(new Tooltip("Create an Alert Dialog"));
create.setOnAction(e ->
{
createAlert();
});
primaryStage.setScene(new Scene(create));
primaryStage.show();
stage = primaryStage;
}
protected Alert createAlert()
{
Alert alert = new Alert(AlertType.WARNING);
Image image1 = new Image("http://www.mcaprojecttraining.com/images/java-big-icon.png");
ImageView imageView = new ImageView(image1);
alert.setGraphic(imageView);
alert.initModality(Modality.APPLICATION_MODAL);
alert.initOwner(stage);
alert.getDialogPane().setContentText("Some text");
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
.ifPresent(response -> System.out.println("The alert was approved"));
return alert;
}
}
I'm interested how I can set the image on the left side of the dialog.
Did someone manage to change the side of the image?
If you have a look at how the header is constructed, you'll find a GridPane node to layout a Label on the left and a StackPane for the icon.
If you want to reverse the cells order by code, you can do it, but it will be overriden every time updateHeaderArea() is called.
My suggestion is using this public API:
dialogPane.setHeader(Node header);
dialogPane.setGraphic(Node graphic);
providing a header with an icon on the left and a label, and a null graphic.
Using the same approach as DialogPane, we could add another GridPane as header:
protected Alert createAlert(){
Alert alert = new Alert(AlertType.WARNING);
alert.initModality(Modality.APPLICATION_MODAL);
alert.initOwner(stage);
alert.getDialogPane().setContentText("Some text");
DialogPane dialogPane = alert.getDialogPane();
GridPane grid = new GridPane();
ColumnConstraints graphicColumn = new ColumnConstraints();
graphicColumn.setFillWidth(false);
graphicColumn.setHgrow(Priority.NEVER);
ColumnConstraints textColumn = new ColumnConstraints();
textColumn.setFillWidth(true);
textColumn.setHgrow(Priority.ALWAYS);
grid.getColumnConstraints().setAll(graphicColumn, textColumn);
grid.setPadding(new Insets(5));
Image image1 = new Image("http://www.mcaprojecttraining.com/images/java-big-icon.png");
ImageView imageView = new ImageView(image1);
imageView.setFitWidth(64);
imageView.setFitHeight(64);
StackPane stackPane = new StackPane(imageView);
stackPane.setAlignment(Pos.CENTER);
grid.add(stackPane, 0, 0);
Label headerLabel = new Label("Warning");
headerLabel.setWrapText(true);
headerLabel.setAlignment(Pos.CENTER_RIGHT);
headerLabel.setMaxWidth(Double.MAX_VALUE);
headerLabel.setMaxHeight(Double.MAX_VALUE);
grid.add(headerLabel, 1, 0);
dialogPane.setHeader(grid);
dialogPane.setGraphic(null);
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
.ifPresent(response -> System.out.println("The alert was approved"));
return alert;
}
And this is what you will see:

Sort TreeView by name

I have this very simple example of TreeView.
import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;
public class TreeTableViewSample extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
stage.setTitle("Tree Table View Samples");
final Scene scene = new Scene(new Group(), 200, 400);
Group sceneRoot = (Group)scene.getRoot();
//Creating tree items
final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1");
final TreeItem<String> childNode2 = new TreeItem<>("Child Node 2");
final TreeItem<String> childNode3 = new TreeItem<>("Child Node 3");
//Creating the root element
final TreeItem<String> root = new TreeItem<>("Root node");
root.setExpanded(true);
//Adding tree items to the root
root.getChildren().setAll(childNode1, childNode2, childNode3);
//Creating a column
TreeTableColumn<String,String> column = new TreeTableColumn<>("Column");
column.setPrefWidth(150);
//Defining cell content
column.setCellValueFactory((CellDataFeatures<String, String> p) ->
new ReadOnlyStringWrapper(p.getValue().getValue()));
//Creating a tree table view
final TreeTableView<String> treeTableView = new TreeTableView<>(root);
treeTableView.getColumns().add(column);
treeTableView.setPrefWidth(152);
treeTableView.setShowRoot(true);
sceneRoot.getChildren().add(treeTableView);
stage.setScene(scene);
stage.show();
}
}
I'm interested how I can sort the tree nodes by name?
Is this functionality already implemented in JavaFX or I need to implement custom tree cell?
Is there any example that I can use?
By default, the items on every TableColumn can be sorted just by clicking on its header, once or twice, to get the default sort order (ascending or descending by default).
The default comparator is String.compareTo, which compares two strings lexicographically.
But you can implement your own. For instance, this will sort by the length of the strings:
// compare by length of the strings
column.setComparator(Comparator.comparing(String::length));
And this one will sort first by length, then in case of equal length, by name:
// compare by length first, and then lexicographically
column.setComparator(Comparator.comparing(String::length).thenComparing(String::compareTo));
EDIT: Since the example refers to a TreeTableView, but the OP asks for a TreeView, this is how the items can be sorted:
1) Since we are adding a collection of items, we can sort it before adding the children to the root
#Override
public void start(Stage stage) {
stage.setTitle("Tree Table View Samples");
final Scene scene = new Scene(new Group(), 200, 400);
Group sceneRoot = (Group)scene.getRoot();
//Creating tree items
final TreeItem<String> childNode1 = new TreeItem<>("Child Node 10");
final TreeItem<String> childNode2 = new TreeItem<>("Child Node Two");
final TreeItem<String> childNode3 = new TreeItem<>("Child Node 3");
//Creating the root element
final TreeItem<String> root = new TreeItem<>("Root node");
root.setExpanded(true);
List<TreeItem<String>> list = Arrays.asList(childNode1, childNode2, childNode3);
// sort by length of the item's names
list.sort(Comparator.comparing(t->t.getValue().length()));
//Adding tree items to the root
root.getChildren().setAll(list);
TreeView<String> tree = new TreeView<> (root);
sceneRoot.getChildren().add(tree);
stage.setScene(scene);
stage.show();
}
2) Once we have added the items to the root we can provide a Comparator to the root:
#Override
public void start(Stage stage) {
stage.setTitle("Tree Table View Samples");
final Scene scene = new Scene(new Group(), 200, 400);
Group sceneRoot = (Group)scene.getRoot();
//Creating tree items
final TreeItem<String> childNode1 = new TreeItem<>("Child Node 10");
final TreeItem<String> childNode2 = new TreeItem<>("Child Node Two");
final TreeItem<String> childNode3 = new TreeItem<>("Child Node 3");
//Creating the root element
final TreeItem<String> root = new TreeItem<>("Root node");
root.setExpanded(true);
//Adding tree items to the root
root.getChildren().setAll(childNode1, childNode2, childNode3);
TreeView<String> tree = new TreeView<> (root);
// sort by length of the item's names
root.getChildren().sort(Comparator.comparing(t->t.getValue().length()));
sceneRoot.getChildren().add(tree);
stage.setScene(scene);
stage.show();
}

Resources