Discussions
Categories
- 197K All Categories
- 2.5K Data
- 546 Big Data Appliance
- 1.9K Data Science
- 450.8K Databases
- 221.9K General Database Discussions
- 3.8K Java and JavaScript in the Database
- 31 Multilingual Engine
- 552 MySQL Community Space
- 479 NoSQL Database
- 7.9K Oracle Database Express Edition (XE)
- 3.1K ORDS, SODA & JSON in the Database
- 556 SQLcl
- 4K SQL Developer Data Modeler
- 187.2K SQL & PL/SQL
- 21.4K SQL Developer
- 296.4K Development
- 17 Developer Projects
- 139 Programming Languages
- 293.1K Development Tools
- 110 DevOps
- 3.1K QA/Testing
- 646.1K Java
- 28 Java Learning Subscription
- 37K Database Connectivity
- 159 Java Community Process
- 105 Java 25
- 22.1K Java APIs
- 138.2K Java Development Tools
- 165.3K Java EE (Java Enterprise Edition)
- 19 Java Essentials
- 162 Java 8 Questions
- 86K Java Programming
- 81 Java Puzzle Ball
- 65.1K New To Java
- 1.7K Training / Learning / Certification
- 13.8K Java HotSpot Virtual Machine
- 94.3K Java SE
- 13.8K Java Security
- 205 Java User Groups
- 24 JavaScript - Nashorn
- Programs
- 471 LiveLabs
- 39 Workshops
- 10.2K Software
- 6.7K Berkeley DB Family
- 3.5K JHeadstart
- 5.7K Other Languages
- 2.3K Chinese
- 175 Deutsche Oracle Community
- 1.1K Español
- 1.9K Japanese
- 233 Portuguese
implementing Toggle in javafx ComboBox

While using SolidWorks 2013, I came across this type of ComboBox which also operates as a ToggleButton:
I was wondering if I can somehow create such Toggle-ComboBox.
After a little research, I found that I have 3 options:
- Using a SplitMenuButton.
This option has numerous propblems, such as, it doesn't have a value property.
That creates a problem because the caption never changes with the action of MenuItems.
2. Using a ComboBox setting the property 'editable' to true, which looks like this:
But it's problem is that, in the 'Button cell', there is a TextField, which I really don't want.
3. Making my own custom control for this.
Now, is there anything I can do with the first two options? That will be better. If not, what will be the best way to create a custom one?
Best Answer
-
It's not that hard to do it:
public class Main extends Application { @Override public void start(final Stage primaryStage) { // Creates items for menu button. final ToggleGroup toogleGroup = new ToggleGroup(); final MenuItem[] menus = IntStream.range(0, 10) .mapToObj(index -> { final RadioMenuItem menuItem = new RadioMenuItem(); menuItem.setText(String.format("Radio #%d", index + 1)); menuItem.setToggleGroup(toogleGroup); menuItem.setOnAction(event -> System.out.printf("Action -> %s%n", menuItem.getText())); return menuItem; }) .toArray(MenuItem[]::new); toogleGroup.getToggles().get(0).setSelected(true); // Creates menu button. final SplitMenuButton splitMenuButton = new SplitMenuButton(); // Forward action to selected item when button is clicked. // Works ok but logs warnings when the selected toggle is briefly null when the selection changes.// splitMenuButton.onActionProperty().bind(Bindings.select(toogleGroup.selectedToggleProperty(), "onAction")); // Works ok without warnings. splitMenuButton.setOnAction(event -> { Optional.ofNullable((RadioMenuItem) toogleGroup.getSelectedToggle()) .ifPresent(menuItem -> { Optional.ofNullable(menuItem.getOnAction()) .ifPresent(eventHandler -> eventHandler.handle(event)); }); }); // Bind item's text to button. splitMenuButton.textProperty().bind(new StringBinding() { { bind(toogleGroup.selectedToggleProperty()); } @Override public void dispose() { unbind(toogleGroup.selectedToggleProperty()); super.dispose(); } @Override protected String computeValue() { final RadioMenuItem menuItem = (RadioMenuItem) toogleGroup.getSelectedToggle(); String result = (menuItem == null) ? null : menuItem.getText(); return result; } }); // Bind item's graphic to button. splitMenuButton.graphicProperty().bind(new ObjectBinding<Node>() { { bind(toogleGroup.selectedToggleProperty()); } @Override public void dispose() { unbind(toogleGroup.selectedToggleProperty()); super.dispose(); } @Override protected Node computeValue() { final RadioMenuItem menuItem = (RadioMenuItem) toogleGroup.getSelectedToggle(); final Node result = null; // Find a way to duplicate graphic here. // final Node result = (menuItem == null) ? null : duplicateGraphic(menuItem.getGraphic()); return result; } }); splitMenuButton.getItems().setAll(menus); final StackPane root = new StackPane(); root.getChildren().add(splitMenuButton); final Scene scene = new Scene(root, 300, 250); primaryStage.setTitle("Test"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(final String[] args) { launch(args); }}
Answers
-
It's not that hard to do it:
public class Main extends Application { @Override public void start(final Stage primaryStage) { // Creates items for menu button. final ToggleGroup toogleGroup = new ToggleGroup(); final MenuItem[] menus = IntStream.range(0, 10) .mapToObj(index -> { final RadioMenuItem menuItem = new RadioMenuItem(); menuItem.setText(String.format("Radio #%d", index + 1)); menuItem.setToggleGroup(toogleGroup); menuItem.setOnAction(event -> System.out.printf("Action -> %s%n", menuItem.getText())); return menuItem; }) .toArray(MenuItem[]::new); toogleGroup.getToggles().get(0).setSelected(true); // Creates menu button. final SplitMenuButton splitMenuButton = new SplitMenuButton(); // Forward action to selected item when button is clicked. // Works ok but logs warnings when the selected toggle is briefly null when the selection changes.// splitMenuButton.onActionProperty().bind(Bindings.select(toogleGroup.selectedToggleProperty(), "onAction")); // Works ok without warnings. splitMenuButton.setOnAction(event -> { Optional.ofNullable((RadioMenuItem) toogleGroup.getSelectedToggle()) .ifPresent(menuItem -> { Optional.ofNullable(menuItem.getOnAction()) .ifPresent(eventHandler -> eventHandler.handle(event)); }); }); // Bind item's text to button. splitMenuButton.textProperty().bind(new StringBinding() { { bind(toogleGroup.selectedToggleProperty()); } @Override public void dispose() { unbind(toogleGroup.selectedToggleProperty()); super.dispose(); } @Override protected String computeValue() { final RadioMenuItem menuItem = (RadioMenuItem) toogleGroup.getSelectedToggle(); String result = (menuItem == null) ? null : menuItem.getText(); return result; } }); // Bind item's graphic to button. splitMenuButton.graphicProperty().bind(new ObjectBinding<Node>() { { bind(toogleGroup.selectedToggleProperty()); } @Override public void dispose() { unbind(toogleGroup.selectedToggleProperty()); super.dispose(); } @Override protected Node computeValue() { final RadioMenuItem menuItem = (RadioMenuItem) toogleGroup.getSelectedToggle(); final Node result = null; // Find a way to duplicate graphic here. // final Node result = (menuItem == null) ? null : duplicateGraphic(menuItem.getGraphic()); return result; } }); splitMenuButton.getItems().setAll(menus); final StackPane root = new StackPane(); root.getChildren().add(splitMenuButton); final Scene scene = new Scene(root, 300, 250); primaryStage.setTitle("Test"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(final String[] args) { launch(args); }}
-
Wow! works fine. I appreciate it. Thanks a lot.