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

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); }
}

Related

Javafx TilePane PrefColumns

I am having problems producing the correct number of columns in a TilePane row.
I'm trying just to have ten columns per row. I know I'm missing the obvious. So, I need another pair of eyes.
The setPrefColumns method does not appear to work the way I have it coded.
#SuppressWarnings("unused")
public class Main extends Application {
TilePane tp = new TilePane();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
primaryStage.setResizable(false);
tp.setPrefColumns(10);
setTP();
Scene scene = new Scene(tp,800,600);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public void setTP() {
tp.setVisible(true);
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
for(int row=0; row<11; row++) {
for (int i: numbers ) {
Text t = new Text(String.valueOf(i));
HBox hbox = new HBox();
hbox.getChildren().add(t);
hbox.setStyle("-fx-border-color: red;");
tp.getChildren().add(hbox);
}
}
}
}
Your example TilePane behaves as specified:
Note that prefColumns/prefRows is used only for calculating the preferred size and may not reflect the actual number of rows or columns, which may change as the tilepane is resized and the tiles are wrapped at its actual boundaries.
As root of the scene it is sized to fill the complete width (800 in your context):
Scene scene = new Scene(tp,800,600);
To make it wrap on its prefColumns, you need to add it to a layout that respects its content's prefWidth, f.i. a HBox:
Scene scene = new Scene(new HBox(tp),800,600);

Add JavaFX Label - (Using Only Java / JavaFX Code) - To Existing GUI Created With Scenebuilder / FXML

I Created a complete GUI using ONLY Scenebuilder FXML Techniques
Something Like This :-
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception{
Parent root=FXMLLoader.load(getClass().getResource("backupmenu.fxml"));
primaryStage.setTitle("Backup Affected Files And Folders Only");
primaryStage.setScene(new Scene( root, 800, 400));
primaryStage.show();
}
}
However I want to add a label to that SAME EXISTING GUI but this time using ONLY Java Code / JavaFX Label Techniques ?
I.E Using Traditional Methods such as this Example Below :-
// launch the application
public void start(Stage s)
{
// set title for the stage
s.setTitle("creating label");
// create a label
Label b = new Label("This is a label");
// create a Stack pane
StackPane rootpane = new StackPane();
// add password field
rootpane.getChildren().add(b);
// create a scene
Scene sc = new Scene(rootpane, 200, 200);
// set the scene
s.setScene(sc);
s.show();
}
public static void main(String args[])
{
// launch the application
launch(args);
}
}
I cannot find a web search result that even comes close to matching my very specific question .
Can i combine the 2 techniques - Is it Possible ?
Yes, this is possible.
You need a reference to the Parent (some kind of container Pane or Node) you want to add the Label to in your controller class.
For example, suppose your FXML defines a VBox with an id of "root":
<VBox fx:id="root">
In your controller, define a reference to that VBox:
#FXML
private VBox root;
Then you can add anything you want to the VBox:
root.getChildren().add(new Label("Hi, I'm a new Label!"));

How to listen to on selected event in choice box javafx

Im using scenebuilder and I have come up with 3 choiceboxes. The second choicebox depends on the input of the first choicebox and the third depends on the 2nd. How can I achieve this?
I've tried this
#FXML
private ChoiceBox course;
course.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov,
Number old_val, Number new_val) -> {
//some code here
}
);
But this event only occurs if i switch value, the first selection would not trigger this event, which is not what I want.
How can I achieve this, thanks in advance.
You can do something like this where everytime an action is done it will set the values of the next one. Make note of the .getItems().clear(); this will ensure the list is emptied everytime so that you don't have old values in the list. The for loop however is not important only there to add some variety to the text values I added
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
ChoiceBox<String> choiceBoxOne = new ChoiceBox<>();
choiceBoxOne.setPrefWidth(100);
choiceBoxOne.getItems().addAll("Choice1", "Choice2", "Choice3");
ChoiceBox<String> choiceBoxTwo = new ChoiceBox<>();
choiceBoxTwo.setPrefWidth(100);
ChoiceBox<String> choiceBoxThree = new ChoiceBox<>();
choiceBoxThree.setPrefWidth(100);
choiceBoxOne.setOnAction(event -> {
choiceBoxTwo.getItems().clear();
//The above line is important otherwise everytime there is an action it will just keep adding more
if(choiceBoxOne.getValue()!=null) {//This cannot be null but I added because idk what yours will look like
for (int i = 3; i < 6; i++) {
choiceBoxTwo.getItems().add(choiceBoxOne.getValue() + i);
}
}
});
choiceBoxTwo.setOnAction(event -> {
choiceBoxThree.getItems().clear();
//The above line is important otherwise everytime there is an action it will just keep adding more
if(choiceBoxTwo.getValue()!=null) {//This can be null if ChoiceBoxOne is changed
for (int i = 6; i < 9; i++) {
choiceBoxThree.getItems().add(choiceBoxTwo.getValue() + i);
}
}
});
VBox vBox = new VBox();
vBox.setPrefSize(300, 300);
vBox.setAlignment(Pos.TOP_CENTER);
vBox.getChildren().addAll(choiceBoxOne, choiceBoxTwo, choiceBoxThree);
primaryStage.setScene(new Scene(vBox));
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}

How to disable right click on a menu in javafx

In javaFX code, a menu can popup by left click or right click. How to disable right click?
public void start(Stage primaryStage)
{
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
When I right click the "hello" menu, it will popup menuitem "laugh".
The basic approach is to register a eventFilter on the MenuBar that consumes the events that should not be delivered to the children.
Doing so manually in your application code:
public class DisableRightClickOpenMenu extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you want this behaviour across all your applications, you can implement a custom menuBarSkin that registers the filter and install the custom skin via a stylesheet.
The skin:
public class ExMenuBarSkin extends MenuBarSkin {
/**
* Instantiates a skin for the given MenuBar. Registers an
* event filter that consumes right mouse press.
*
* #param menuBar
*/
public ExMenuBarSkin(MenuBar menuBar) {
super(menuBar);
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
}
}
In your stylesheet (replace with your fully qualified class name):
.menu-bar {
-fx-skin: "de.swingempire.fx.event.ExMenuBarSkin";
}
Its usage (replace the name with your stylesheet file name):
URL uri = getClass().getResource("contextskin.css");
primaryStage.getScene().getStylesheets().add(uri.toExternalForm());
This is usual behavior of menu in many programs. I don't think you can change it. However, you can use some other controls and simulate menu. (Like HBox and Labels).
I agree as far as I know there's no a standard way to do this, but you may want to consider the following workaround.
It is replacing the Menu node with a Menu object composed by an HBox and a Label: an EventHandler is added to the HBox and by checking the mouse button pressed we add/remove on the fly the MenuItem to its parent.
#Override
public void start(final Stage primaryStage) {
final BorderPane root = new BorderPane();
final MenuBar menuBar = new MenuBar();
final Menu menuHello = new Menu();
final Menu menuWorld = new Menu("world");
final MenuItem menuitem = new MenuItem("laugh");
final HBox hbox = new HBox();
menuBar.getMenus().addAll(menuHello, menuWorld);
root.setCenter(menuBar);
hbox.setPrefWidth(30);
hbox.getChildren().add(new Label("hello"));
menuHello.setGraphic(hbox);
menuHello.getItems().add(menuitem);
hbox.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent e) {
if (e.getButton() == MouseButton.SECONDARY) {
System.out.println("Right click");
menuHello.getItems().remove(menuitem);
} else {
System.out.println("Left click");
if (!menuHello.getItems().contains(menuitem)) {
menuHello.getItems().add(menuitem);
menuHello.show(); // The .show method prevent 'losing' the current click }
}
}
});
final Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
This will produce the following result - preview
Note that I've used an HBox just for habit, there's no a particular reason.
While using a workaround like this, my suggestion would be to fill all the Menus with the same 'pattern', such as the HBox + Label combo in my example, and stylize them via css/code (width/height, background/fill/hover... colors etc.) in order to have them as uniform as possible and avoid creating graphic inconsistencies due to have different nodes types in the same menubar.

Sort ObservableList from high to low - javafx

Is there any way to sort a ObservableList based on the values from high to low?
Say I have a
ObservableList<XYChart.Data> data;
containing a String and a Double. I want the list sorted based on the Double from highest to lowest values. The reason I want this is because charts look way better if their values are shown from the highest to the lowest.
I have something like this now:
sortedData = new SortedList<>(data);
sortedData.comparatorProperty().bind(mycomparatorProperty());
You can create a Comparator, compare by the Y value, and then reverse the order:
data.sort(Comparator.comparing(XYChart.Data<String,Double>::getYValue).reversed());
This will sort your collection as intented.
Or you can return a new collection:
List<XYChart.Data<String,Double>> sortedData =
data.stream()
.sorted(Comparator.comparing(XYChart.Data<String,Double>::getYValue).reversed())
.collect(Collectors.toList());
EDIT
For the sake of clarity, this is a full sample:
public class FXMain extends Application {
private final ObservableList<XYChart.Data<String,Double>> data =
FXCollections.observableArrayList(
new XYChart.Data("P1",200d),
new XYChart.Data("P2",150d),
new XYChart.Data("P3",250d));
#Override
public void start(Stage primaryStage) {
Button btn = new Button"Sort data!");
btn.setOnAction(e -> {
ObservableList<XYChart.Data<String,Double>> data2 =
data.stream()
.sorted(Comparator.
comparing(XYChart.Data<String,Double>::getYValue).reversed())
.peek(System.out::println)
.collect(Collectors.toCollection(()->FXCollections.observableArrayList()));
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Resources