├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ └── org │ │ └── modernclients │ │ └── ch3 │ │ └── ch3styles.css │ └── java │ └── org │ └── modernclients │ └── ch3 │ ├── Utils.java │ ├── samples │ ├── HTMLEditorDemo.java │ ├── SeparatorDemo.java │ ├── TitledPaneDemo.java │ ├── HyperlinkDemo.java │ ├── SliderDemo.java │ ├── ButtonDemo.java │ ├── CheckBoxDemo.java │ ├── ScrollBarDemo.java │ ├── TextAreaDemo.java │ ├── ColorPickerDemo.java │ ├── ChoiceBoxDemo.java │ ├── ComboBoxDemo.java │ ├── PasswordFieldDemo.java │ ├── ListViewDemo.java │ ├── MenuButtonDemo.java │ ├── ToolBarDemo.java │ ├── TextFieldDemo.java │ ├── SplitPaneDemo.java │ ├── PaginationDemo.java │ ├── ButtonBarDemo.java │ ├── SplitMenuButtonDemo.java │ ├── RadioButtonDemo.java │ ├── ToggleButtonDemo.java │ ├── ScrollPaneDemo.java │ ├── MenuBarDemo.java │ ├── ProgressBarDemo.java │ ├── TabPaneDemo.java │ ├── ProgressIndicatorDemo.java │ ├── ContextMenuDemo.java │ ├── TableViewDemo.java │ ├── TreeTableViewDemo.java │ ├── TreeViewDemo.java │ ├── AccordionDemo.java │ ├── DialogsDemo.java │ ├── ToolTipDemo.java │ ├── DatePickerDemo.java │ └── SpinnerDemo.java │ ├── Sample.java │ ├── model │ ├── JavaFXNode.java │ └── Person.java │ └── DemoApp.java ├── LICENSE ├── readme.md ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'book' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | hs_err_pid* 2 | *.iml 3 | .idea 4 | build 5 | out 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanGiles/fx-ui-controls/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip 6 | -------------------------------------------------------------------------------- /src/main/resources/org/modernclients/ch3/ch3styles.css: -------------------------------------------------------------------------------- 1 | .root { 2 | -fx-text-box-border: darkgray; 3 | -fx-box-border: darkgray; 4 | } 5 | 6 | .demo-pane, .control-pane { 7 | -fx-border-color: -fx-box-border; 8 | -fx-border-width: 1px; 9 | -fx-padding: 10px; 10 | } 11 | 12 | .control-pane { 13 | 14 | } 15 | 16 | .samples-list { 17 | 18 | } 19 | 20 | .console { 21 | } -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/Utils.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3; 2 | 3 | import javafx.scene.control.MenuItem; 4 | 5 | import java.util.function.Consumer; 6 | 7 | public class Utils { 8 | 9 | private Utils() { } 10 | 11 | public static MenuItem makeMenuItem(String text, Consumer console) { 12 | MenuItem menuItem = new MenuItem(text); 13 | menuItem.setOnAction(e -> console.accept("MenuItem '" + text + "' has been clicked on")); 14 | return menuItem; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/HTMLEditorDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.layout.Pane; 4 | import javafx.scene.web.HTMLEditor; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class HTMLEditorDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | HTMLEditor htmlEditor = new HTMLEditor(); 17 | 18 | container.getChildren().add(htmlEditor); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/SeparatorDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Separator; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class SeparatorDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | Separator separator = new Separator(); 17 | 18 | container.getChildren().add(separator); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TitledPaneDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Button; 4 | import javafx.scene.control.TitledPane; 5 | import javafx.scene.layout.Pane; 6 | import org.modernclients.ch3.Sample; 7 | 8 | import java.util.function.Consumer; 9 | 10 | /** 11 | * @author Jonathan Giles 12 | */ 13 | public class TitledPaneDemo implements Sample { 14 | 15 | @Override 16 | public void buildDemo(Pane container, Consumer console) { 17 | TitledPane t1 = new TitledPane("TitledPane 1", new Button("Button 1")); 18 | 19 | container.getChildren().add(t1); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/HyperlinkDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Hyperlink; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class HyperlinkDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | Hyperlink hyperlink = new Hyperlink("Click Me!"); 17 | hyperlink.setOnAction(event -> console.accept("Hyperlink was clicked")); 18 | 19 | container.getChildren().add(hyperlink); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/SliderDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Slider; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class SliderDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | Slider slider = new Slider(0.0f, 1.0f, 0.5f); 17 | slider.valueProperty().addListener((o, oldValue, newValue) -> console.accept("Slider value is " + newValue)); 18 | 19 | container.getChildren().add(slider); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ButtonDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.Button; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.layout.VBox; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.Optional; 10 | import java.util.function.Consumer; 11 | 12 | /** 13 | * @author Jonathan Giles 14 | */ 15 | public class ButtonDemo implements Sample { 16 | 17 | @Override 18 | public void buildDemo(Pane container, Consumer console) { 19 | Button button = new Button("Click Me!"); 20 | button.setOnAction(event -> console.accept("Button was clicked")); 21 | 22 | container.getChildren().addAll(button); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/CheckBoxDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.CheckBox; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class CheckBoxDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | CheckBox cb = new CheckBox("Enable Power Plant"); 17 | cb.setIndeterminate(false); 18 | cb.setOnAction(e -> console.accept("Action event fired")); 19 | cb.selectedProperty().addListener(i -> console.accept("Selected state change to " + cb.isSelected())); 20 | 21 | container.getChildren().add(cb); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ScrollBarDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.ScrollBar; 4 | import javafx.scene.control.Slider; 5 | import javafx.scene.layout.Pane; 6 | import org.modernclients.ch3.Sample; 7 | 8 | import java.util.function.Consumer; 9 | 10 | /** 11 | * @author Jonathan Giles 12 | */ 13 | public class ScrollBarDemo implements Sample { 14 | 15 | @Override 16 | public void buildDemo(Pane container, Consumer console) { 17 | ScrollBar scrollBar = new ScrollBar(); 18 | scrollBar.setMin(0.0f); 19 | scrollBar.setMax(0.0f); 20 | scrollBar.valueProperty().addListener((o, oldValue, newValue) -> console.accept("ScrollBar value is " + newValue)); 21 | 22 | container.getChildren().add(scrollBar); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TextAreaDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.TextArea; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class TextAreaDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | TextArea textArea = new TextArea(); 17 | textArea.setPromptText("Enter description here"); 18 | 19 | // we can also observe input in real time 20 | textArea.textProperty().addListener((o, oldValue, newValue) -> console.accept("current text input is " + newValue)); 21 | 22 | container.getChildren().add(textArea); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ColorPickerDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.ColorPicker; 4 | import javafx.scene.layout.Pane; 5 | import javafx.scene.paint.Color; 6 | import org.modernclients.ch3.Sample; 7 | 8 | import java.util.function.Consumer; 9 | 10 | /** 11 | * @author Jonathan Giles 12 | */ 13 | public class ColorPickerDemo implements Sample { 14 | 15 | @Override 16 | public void buildDemo(Pane container, Consumer console) { 17 | final ColorPicker colorPicker = new ColorPicker(); 18 | colorPicker.setOnAction(e -> { 19 | Color c = colorPicker.getValue(); 20 | console.accept("New Color's RGB = "+c.getRed()+", "+c.getGreen()+", "+c.getBlue()); 21 | }); 22 | 23 | container.getChildren().add(colorPicker); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/Sample.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.layout.Pane; 5 | 6 | import java.util.Optional; 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public interface Sample extends Comparable { 13 | 14 | void buildDemo(Pane container, Consumer console); 15 | 16 | default String getName() { 17 | String className = getClass().getSimpleName(); 18 | return className.endsWith("Demo") ? 19 | className.substring(0, className.length() - 4) : 20 | "Unknown Demo"; 21 | } 22 | 23 | default Optional buildControlPanel() { 24 | return Optional.empty(); 25 | } 26 | 27 | @Override 28 | default int compareTo(Sample o) { 29 | return getName().compareTo(o.getName()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ChoiceBoxDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.ChoiceBox; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Mohammad Hossein Rimaz 11 | */ 12 | public class ChoiceBoxDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | ChoiceBox choiceBox = new ChoiceBox<>(); 17 | 18 | choiceBox.getItems().addAll( 19 | "Choice 1", 20 | "Choice 2", 21 | "Choice 3", 22 | "Choice 4" 23 | ); 24 | 25 | choiceBox.getSelectionModel() 26 | .selectedItemProperty() 27 | .addListener((o, oldValue, newValue) -> console.accept(newValue)); 28 | 29 | container.getChildren().add(choiceBox); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ComboBoxDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.ComboBox; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | import java.util.stream.IntStream; 9 | 10 | /** 11 | * @author Abhinay Agarwal 12 | */ 13 | public class ComboBoxDemo implements Sample { 14 | 15 | @Override 16 | public void buildDemo(Pane container, Consumer console) { 17 | // Create the ComboBox instance 18 | ComboBox comboBox = new ComboBox<>(); 19 | 20 | // Add items to ComboBox 21 | IntStream.range(1, 100).forEach(i -> comboBox.getItems().add("Item " + i)); 22 | 23 | // Display selected item in console 24 | comboBox.setOnAction(e -> console.accept(comboBox.getSelectionModel().getSelectedItem())); 25 | 26 | container.getChildren().add(comboBox); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/model/JavaFXNode.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.model; 2 | 3 | import javafx.beans.property.SimpleStringProperty; 4 | import javafx.beans.property.StringProperty; 5 | 6 | public class JavaFXNode { 7 | 8 | private StringProperty name = new SimpleStringProperty(); 9 | private StringProperty parent = new SimpleStringProperty(); 10 | 11 | public JavaFXNode(String name, String parent) { 12 | this.name.set(name); 13 | this.parent.set(parent); 14 | } 15 | 16 | public String getName() { 17 | return name.get(); 18 | } 19 | 20 | public StringProperty nameProperty() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name.set(name); 26 | } 27 | 28 | public String getParent() { 29 | return parent.get(); 30 | } 31 | 32 | public StringProperty parentProperty() { 33 | return parent; 34 | } 35 | 36 | public void setParent(String parent) { 37 | this.parent.set(parent); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/PasswordFieldDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.PasswordField; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | /** 10 | * @author Jonathan Giles 11 | */ 12 | public class PasswordFieldDemo implements Sample { 13 | 14 | @Override 15 | public void buildDemo(Pane container, Consumer console) { 16 | PasswordField passwordField = new PasswordField(); 17 | passwordField.setPromptText("Enter password here"); 18 | 19 | // this is fired when the user hits the Enter key 20 | passwordField.setOnAction(e -> console.accept("Entered password is: " + passwordField.getText())); 21 | 22 | // we can also observe input in real time 23 | passwordField.textProperty().addListener((o, oldValue, newValue) -> console.accept("current password input is " + newValue)); 24 | 25 | container.getChildren().add(passwordField); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ListViewDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.ListView; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | import java.util.stream.IntStream; 9 | 10 | /** 11 | * @author Abhinay Agarwal 12 | */ 13 | public class ListViewDemo implements Sample { 14 | 15 | @Override 16 | public void buildDemo(Pane container, Consumer console) { 17 | 18 | // Create the ListView instance 19 | final ListView listView = new ListView<>(); 20 | 21 | // Add items to ListView 22 | IntStream.range(1, 100).forEach(i -> listView.getItems().add("Item " + i)); 23 | 24 | // Display selected item in console 25 | listView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { 26 | console.accept(newValue); 27 | }); 28 | 29 | container.getChildren().add(listView); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/MenuButtonDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.MenuButton; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | import static org.modernclients.ch3.Utils.makeMenuItem; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class MenuButtonDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | MenuButton menuButton = new MenuButton("Choose a meal..."); 19 | menuButton.getItems().addAll( 20 | makeMenuItem("Burgers", console), 21 | makeMenuItem("Pizza", console), 22 | makeMenuItem("Hot Dog", console)); 23 | 24 | // because the MenuButton does not have an 'action' area, onAction does nothing 25 | menuButton.setOnAction(e -> console.accept("MenuButton onAction event")); 26 | 27 | container.getChildren().add(menuButton); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ToolBarDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.*; 4 | import javafx.scene.layout.Pane; 5 | import javafx.scene.paint.Color; 6 | import javafx.scene.shape.Rectangle; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class ToolBarDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | ToolBar toolBar = new ToolBar(); 19 | toolBar.getItems().addAll( 20 | new Button("New"), 21 | new Button("Open"), 22 | new Button("Save"), 23 | new Separator(), 24 | new Button("Clean"), 25 | new Button("Compile"), 26 | new Button("Run"), 27 | new Separator(), 28 | new Button("Debug"), 29 | new Button("Profile") 30 | ); 31 | 32 | container.getChildren().add(toolBar); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jonathan Giles 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TextFieldDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.TextField; 4 | import javafx.scene.control.ToggleButton; 5 | import javafx.scene.control.ToggleGroup; 6 | import javafx.scene.layout.HBox; 7 | import javafx.scene.layout.Pane; 8 | import org.modernclients.ch3.Sample; 9 | 10 | import java.util.function.Consumer; 11 | 12 | /** 13 | * @author Jonathan Giles 14 | */ 15 | public class TextFieldDemo implements Sample { 16 | 17 | @Override 18 | public void buildDemo(Pane container, Consumer console) { 19 | TextField textField = new TextField(); 20 | textField.setPromptText("Enter name here"); 21 | 22 | // this is fired when the user hits the Enter key 23 | textField.setOnAction(e -> console.accept("Entered text is: " + textField.getText())); 24 | 25 | // we can also observe input in real time 26 | textField.textProperty().addListener((o, oldValue, newValue) -> console.accept("current text input is " + newValue)); 27 | 28 | container.getChildren().add(textField); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/SplitPaneDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Button; 4 | import javafx.scene.control.SplitPane; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.layout.StackPane; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class SplitPaneDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | final StackPane sp1 = new StackPane(); 19 | sp1.getChildren().add(new Button("Button One")); 20 | 21 | final StackPane sp2 = new StackPane(); 22 | sp2.getChildren().add(new Button("Button Two")); 23 | 24 | final StackPane sp3 = new StackPane(); 25 | sp3.getChildren().add(new Button("Button Three")); 26 | 27 | SplitPane splitPane = new SplitPane(); 28 | splitPane.getItems().addAll(sp1, sp2, sp3); 29 | splitPane.setDividerPositions(0.3f, 0.6f, 0.9f); 30 | 31 | container.getChildren().add(splitPane); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/PaginationDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Hyperlink; 4 | import javafx.scene.control.Pagination; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.layout.VBox; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class PaginationDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | Pagination pagination = new Pagination(10, 0); 19 | pagination.setPageFactory(pageIndex -> { 20 | VBox box = new VBox(5); 21 | for (int i = 0; i < 10; i++) { 22 | int linkNumber = pageIndex * 10 + i; 23 | Hyperlink link = new Hyperlink("Hyperlink #" + linkNumber); 24 | link.setOnAction(e -> console.accept("Hyperlink #" + linkNumber + " clicked!")); 25 | box.getChildren().add(link); 26 | } 27 | return box; 28 | }); 29 | 30 | container.getChildren().add(pagination); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ButtonBarDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.Button; 5 | import javafx.scene.control.ButtonBar; 6 | import javafx.scene.layout.Pane; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | import static javafx.scene.control.ButtonBar.ButtonData; 12 | 13 | /** 14 | * @author Jonathan Giles 15 | */ 16 | public class ButtonBarDemo implements Sample { 17 | 18 | @Override 19 | public void buildDemo(Pane container, Consumer console) { 20 | // Create the ButtonBar instance 21 | ButtonBar buttonBar = new ButtonBar(); 22 | 23 | // Create the buttons to go into the ButtonBar 24 | Button yesButton = new Button("Yes"); 25 | ButtonBar.setButtonData(yesButton, ButtonData.YES); 26 | 27 | Button noButton = new Button("No"); 28 | ButtonBar.setButtonData(noButton, ButtonData.NO); 29 | 30 | // Add buttons to the ButtonBar 31 | buttonBar.getButtons().addAll(yesButton, noButton); 32 | 33 | container.getChildren().addAll(buttonBar); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/SplitMenuButtonDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.SplitMenuButton; 4 | import javafx.scene.layout.Pane; 5 | import org.modernclients.ch3.Sample; 6 | 7 | import java.util.function.Consumer; 8 | 9 | import static org.modernclients.ch3.Utils.makeMenuItem; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class SplitMenuButtonDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | SplitMenuButton splitMenuButton = new SplitMenuButton(); 19 | 20 | // this is the text in the 'action' area 21 | splitMenuButton.setText("Perform action!"); 22 | 23 | // these are the menu items to display in the popup menu 24 | splitMenuButton.getItems().addAll( 25 | makeMenuItem("Burgers", console), 26 | makeMenuItem("Pizza", console), 27 | makeMenuItem("Hot Dog", console)); 28 | 29 | // splitMenuButton does fire an onAction event, when the 'action' area is pressed 30 | splitMenuButton.setOnAction(e -> console.accept("SplitMenuButton onAction event")); 31 | 32 | container.getChildren().add(splitMenuButton); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/RadioButtonDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.RadioButton; 4 | import javafx.scene.control.ToggleGroup; 5 | import javafx.scene.layout.HBox; 6 | import javafx.scene.layout.Pane; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class RadioButtonDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | // create a few radio buttons 19 | RadioButton rb1 = new RadioButton("Radio button 1"); 20 | RadioButton rb2 = new RadioButton("Radio button 2"); 21 | RadioButton rb3 = new RadioButton("Radio button 3"); 22 | 23 | // create a toggle group and add all the radio buttons to it 24 | ToggleGroup group = new ToggleGroup(); 25 | group.getToggles().addAll(rb1, rb2, rb3); 26 | 27 | // it is possible to add an onAction listener for each button 28 | rb1.setOnAction(e -> console.accept("RadioButton 1 was clicked on!")); 29 | 30 | // but generally it is better to just add a listener to the toggle group selectedToggle property 31 | group.selectedToggleProperty().addListener(i -> console.accept("Selected toggle is " + group.getSelectedToggle())); 32 | 33 | HBox hbox = new HBox(rb1, rb2, rb3); 34 | container.getChildren().add(hbox); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ToggleButtonDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.ToggleButton; 4 | import javafx.scene.control.ToggleGroup; 5 | import javafx.scene.layout.HBox; 6 | import javafx.scene.layout.Pane; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * @author Jonathan Giles 13 | */ 14 | public class ToggleButtonDemo implements Sample { 15 | 16 | @Override 17 | public void buildDemo(Pane container, Consumer console) { 18 | // create a few toggle buttons 19 | ToggleButton tb1 = new ToggleButton("Toggle button 1"); 20 | ToggleButton tb2 = new ToggleButton("Toggle button 2"); 21 | ToggleButton tb3 = new ToggleButton("Toggle button 3"); 22 | 23 | // create a toggle group and add all the toggle buttons to it 24 | ToggleGroup group = new ToggleGroup(); 25 | group.getToggles().addAll(tb1, tb2, tb3); 26 | 27 | // it is possible to add an onAction listener for each button 28 | tb1.setOnAction(e -> console.accept("ToggleButton 1 was clicked on!")); 29 | 30 | // but generally it is better to just add a listener to the toggle group selectedToggle property 31 | group.selectedToggleProperty().addListener(i -> console.accept("Selected toggle is " + group.getSelectedToggle())); 32 | 33 | HBox hbox = new HBox(tb1, tb2, tb3); 34 | container.getChildren().add(hbox); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # JavaFX UI Controls Sample App 2 | 3 | ![Demo Application](https://jogiles.blob.core.windows.net/misc/modern-java-ch3-app.png) 4 | 5 | This is a project to demonstrate all JavaFX UI controls in a simplistic way. To run, simply use the embedded gradle wrapper: 6 | 7 | MacOS / Linux: 8 | ```./gradlew clean assemble run``` 9 | 10 | Windows: 11 | ```gradlew clean assemble run``` 12 | 13 | ## Contributing 14 | If you are keen to contribute to this project to get good samples - thanks so much! 15 | 16 | We use the standard GitHub pull request approach. So, for this repo, push changes to your fork, and then create a pull request. I will then review and merge. Here's some important tips: 17 | 18 | 1. When you want to work on a sample, file an issue to make sure no one else is working on it. If you already see an issue with your sample, don't work on it! 19 | 1. Check out ButtonDemo for an example of the proof of concept 'control panel'. If you want to toggle state in the UI controls, put the controls in the control panel area of your sample. 20 | 1. If you want to log to the console area, use the `console.accept("text")` approach that you see in other demos. 21 | 1. Keep things simple - don't over complicate the demos - the intent is to teach newcomers to JavaFX how to use the JavaFX UI controls. These demos may also make their way into the JavaFX book chapter that I (Jonathan) am writing. 22 | 1. Feel free to add an `@author Jonathan Giles ` style javadoc annotation to any sample you write. I haven't done that for myself yet, but I encourage contributors to do this to highlight their own contributions. 23 | 24 | Thanks! 25 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ScrollPaneDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.beans.value.ChangeListener; 4 | import javafx.scene.control.Button; 5 | import javafx.scene.control.ButtonBar; 6 | import javafx.scene.control.ScrollPane; 7 | import javafx.scene.layout.Pane; 8 | import javafx.scene.paint.Color; 9 | import javafx.scene.paint.CycleMethod; 10 | import javafx.scene.paint.LinearGradient; 11 | import javafx.scene.paint.Stop; 12 | import javafx.scene.shape.Rectangle; 13 | import org.modernclients.ch3.Sample; 14 | 15 | import java.util.Observable; 16 | import java.util.function.Consumer; 17 | 18 | import static javafx.scene.control.ButtonBar.ButtonData; 19 | 20 | /** 21 | * @author Jonathan Giles 22 | */ 23 | public class ScrollPaneDemo implements Sample { 24 | 25 | @Override 26 | public void buildDemo(Pane container, Consumer console) { 27 | Stop[] stops = new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.RED)}; 28 | LinearGradient gradient = new LinearGradient(0, 0, 1500, 1000, false, CycleMethod.NO_CYCLE, stops); 29 | 30 | Rectangle rect = new Rectangle(2000, 2000, gradient); 31 | ScrollPane scrollPane = new ScrollPane(); 32 | scrollPane.setPrefSize(120, 120); 33 | scrollPane.setContent(rect); 34 | 35 | ChangeListener o = 36 | (obs, oldValue, newValue) -> console.accept("x / y values are: (" + scrollPane.getHvalue() + ", " + scrollPane.getVvalue() + ")"); 37 | scrollPane.hvalueProperty().addListener(o); 38 | scrollPane.vvalueProperty().addListener(o); 39 | 40 | container.getChildren().add(scrollPane); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/model/Person.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.model; 2 | 3 | import javafx.beans.property.ObjectProperty; 4 | import javafx.beans.property.SimpleObjectProperty; 5 | import javafx.beans.property.SimpleStringProperty; 6 | import javafx.beans.property.StringProperty; 7 | 8 | public class Person { 9 | 10 | private StringProperty firstName = new SimpleStringProperty(); 11 | private StringProperty lastName = new SimpleStringProperty(); 12 | private ObjectProperty gender = new SimpleObjectProperty<>(); 13 | 14 | public Person(String firstName, String lastName, Gender gender) { 15 | this.firstName.set(firstName); 16 | this.lastName.set(lastName); 17 | this.gender.set(gender); 18 | } 19 | 20 | public String getFirstName() { 21 | return firstName.get(); 22 | } 23 | 24 | public StringProperty firstNameProperty() { 25 | return firstName; 26 | } 27 | 28 | public void setFirstName(String firstName) { 29 | this.firstName.set(firstName); 30 | } 31 | 32 | public String getLastName() { 33 | return lastName.get(); 34 | } 35 | 36 | public StringProperty lastNameProperty() { 37 | return lastName; 38 | } 39 | 40 | public void setLastName(String lastName) { 41 | this.lastName.set(lastName); 42 | } 43 | 44 | public Gender getGender() { 45 | return gender.get(); 46 | } 47 | 48 | public ObjectProperty genderProperty() { 49 | return gender; 50 | } 51 | 52 | public void setGender(Gender gender) { 53 | this.gender.set(gender); 54 | } 55 | 56 | public enum Gender { 57 | Male, 58 | Female 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/MenuBarDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.control.Menu; 4 | import javafx.scene.control.MenuBar; 5 | import javafx.scene.control.SeparatorMenuItem; 6 | import javafx.scene.layout.Pane; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.function.Consumer; 10 | 11 | import static org.modernclients.ch3.Utils.makeMenuItem; 12 | 13 | /** 14 | * @author Jonathan Giles 15 | */ 16 | public class MenuBarDemo implements Sample { 17 | 18 | @Override 19 | public void buildDemo(Pane container, Consumer console) { 20 | // Firstly we create our menu instances (and populate with menu items) 21 | final Menu fileMenu = new Menu("File"); 22 | final Menu helpMenu = new Menu("Help"); 23 | 24 | // we are creating a Menu here to add as a submenu to the File menu 25 | Menu newMenu = new Menu("Create New..."); 26 | newMenu.getItems().addAll( 27 | makeMenuItem("Project", console), 28 | makeMenuItem("JavaFX class", console), 29 | makeMenuItem("FXML file", console) 30 | ); 31 | 32 | // add menu items to each menu 33 | fileMenu.getItems().addAll( 34 | newMenu, 35 | new SeparatorMenuItem(), 36 | makeMenuItem("Exit", console) 37 | ); 38 | helpMenu.getItems().addAll(makeMenuItem("Help", console)); 39 | 40 | // then we create the MenuBar instance and add in the menus 41 | MenuBar menuBar = new MenuBar(); 42 | menuBar.getMenus().addAll(fileMenu, helpMenu); 43 | 44 | container.getChildren().add(menuBar); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ProgressBarDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.*; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.layout.VBox; 7 | import org.modernclients.ch3.Sample; 8 | 9 | import java.util.Optional; 10 | import java.util.function.Consumer; 11 | 12 | /** 13 | * @author Jonathan Giles 14 | */ 15 | public class ProgressBarDemo implements Sample { 16 | // No initial value of the ProgressBar is set, so will have an indeterminate indicator 17 | final ProgressBar progressBar = new ProgressBar(); 18 | 19 | @Override 20 | public void buildDemo(Pane container, Consumer console) { 21 | container.getChildren().addAll(progressBar); 22 | } 23 | 24 | @Override 25 | public Optional buildControlPanel() { 26 | CheckBox indeterminateCheckBox = new CheckBox(); 27 | indeterminateCheckBox.setSelected(true); 28 | 29 | Slider progressSlider = new Slider(0.0f, 1.0f, 0.5f); 30 | progressSlider.disableProperty().bind(indeterminateCheckBox.selectedProperty()); 31 | 32 | indeterminateCheckBox.selectedProperty().addListener(o -> { 33 | if (indeterminateCheckBox.isSelected()) { 34 | progressBar.progressProperty().unbind(); 35 | progressBar.setProgress(-1); 36 | } else { 37 | progressBar.progressProperty().bind(progressSlider.valueProperty()); 38 | } 39 | }); 40 | 41 | VBox vBox = new VBox(10, 42 | new Label("Indeterminate:"), 43 | indeterminateCheckBox, 44 | new Label("Progress:"), 45 | progressSlider); 46 | return Optional.of(vBox); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TabPaneDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.CheckBox; 5 | import javafx.scene.control.Tab; 6 | import javafx.scene.control.TabPane; 7 | import javafx.scene.layout.Pane; 8 | import javafx.scene.layout.VBox; 9 | import javafx.scene.paint.Color; 10 | import javafx.scene.shape.Rectangle; 11 | import org.modernclients.ch3.Sample; 12 | 13 | import java.util.Optional; 14 | import java.util.Random; 15 | import java.util.function.Consumer; 16 | 17 | /** 18 | * @author Jonathan Giles 19 | */ 20 | public class TabPaneDemo implements Sample { 21 | 22 | private TabPane tabPane; 23 | 24 | @Override 25 | public void buildDemo(Pane container, Consumer console) { 26 | tabPane = new TabPane(); 27 | tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE); 28 | 29 | for (int i = 0; i < 5; i++) { 30 | Tab tab = new Tab("Tab " + i, new Rectangle(200, 200, randomColor())); 31 | tabPane.getTabs().add(tab); 32 | } 33 | 34 | container.getChildren().add(tabPane); 35 | } 36 | 37 | @Override 38 | public Optional buildControlPanel() { 39 | // toggle between standard and floating modes 40 | CheckBox floating = new CheckBox("Floating"); 41 | floating.selectedProperty().addListener(i -> { 42 | tabPane.getStyleClass().remove(TabPane.STYLE_CLASS_FLOATING); 43 | if (floating.isSelected()) tabPane.getStyleClass().add(TabPane.STYLE_CLASS_FLOATING); 44 | }); 45 | 46 | VBox vbox = new VBox(floating); 47 | return Optional.of(vbox); 48 | } 49 | 50 | private Color randomColor() { 51 | Random r = new Random(); 52 | return Color.rgb(r.nextInt(256), r.nextInt(256), r.nextInt(256), 1.0); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ProgressIndicatorDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.*; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.layout.VBox; 7 | 8 | import org.modernclients.ch3.Sample; 9 | 10 | import java.util.Optional; 11 | import java.util.function.Consumer; 12 | 13 | /** 14 | * @author Jonathan Giles 15 | * @author Frank Delporte 16 | */ 17 | public class ProgressIndicatorDemo implements Sample { 18 | // No initial value of the ProgressIndicator is set, so will have an indeterminate indicator 19 | final ProgressIndicator progressIndicator = new ProgressIndicator(); 20 | 21 | @Override 22 | public void buildDemo(Pane container, Consumer console) { 23 | progressIndicator.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); 24 | container.getChildren().addAll(progressIndicator); 25 | } 26 | 27 | @Override 28 | public Optional buildControlPanel() { 29 | CheckBox indeterminateCheckBox = new CheckBox(); 30 | indeterminateCheckBox.setSelected(true); 31 | 32 | Slider progressSlider = new Slider(0.0f, 1.0f, 0.5f); 33 | progressSlider.disableProperty().bind(indeterminateCheckBox.selectedProperty()); 34 | 35 | indeterminateCheckBox.selectedProperty().addListener(o -> { 36 | if (indeterminateCheckBox.isSelected()) { 37 | progressIndicator.progressProperty().unbind(); 38 | progressIndicator.setProgress(-1); 39 | } else { 40 | progressIndicator.progressProperty().bind(progressSlider.valueProperty()); 41 | } 42 | }); 43 | 44 | VBox vBox = new VBox(10, 45 | new Label("Indeterminate:"), 46 | indeterminateCheckBox, 47 | new Label("Progress:"), 48 | progressSlider); 49 | return Optional.of(vBox); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ContextMenuDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.geometry.Side; 4 | import javafx.scene.control.*; 5 | import javafx.scene.layout.BorderPane; 6 | import javafx.scene.layout.HBox; 7 | import javafx.scene.layout.Pane; 8 | import javafx.scene.paint.Color; 9 | import javafx.scene.shape.Rectangle; 10 | import org.modernclients.ch3.Sample; 11 | 12 | import java.util.function.Consumer; 13 | 14 | import static org.modernclients.ch3.Utils.makeMenuItem; 15 | 16 | /** 17 | * @author Jonathan Giles 18 | */ 19 | public class ContextMenuDemo implements Sample { 20 | 21 | @Override 22 | public void buildDemo(Pane container, Consumer console) { 23 | // create a standard JavaFX Button 24 | Button button = new Button("Right-click Me!"); 25 | button.setOnAction(event -> console.accept("Button was clicked")); 26 | button.setContextMenu(makeContextMenu(console)); 27 | 28 | ContextMenu rectangleContextMenu = makeContextMenu(console); 29 | Rectangle rectangle = new Rectangle(50, 50, Color.RED); 30 | rectangle.setOnContextMenuRequested(e -> { 31 | // show the contextMenu to the right of the rectangle with zero 32 | // offset in x and y directions 33 | rectangleContextMenu.show(rectangle, Side.RIGHT, 0, 0); 34 | }); 35 | 36 | BorderPane borderPane = new BorderPane(); 37 | borderPane.setTop(new Label("Right-click the following nodes for a context menu:")); 38 | borderPane.setCenter(new HBox(10, button, rectangle)); 39 | 40 | container.getChildren().addAll(borderPane); 41 | } 42 | 43 | private ContextMenu makeContextMenu(Consumer console) { 44 | // create a ContextMenu 45 | ContextMenu contextMenu = new ContextMenu(); 46 | contextMenu.getItems().addAll( 47 | makeMenuItem("Hello", console), 48 | makeMenuItem("World!", console), 49 | new SeparatorMenuItem(), 50 | makeMenuItem("Goodbye Again!", console) 51 | ); 52 | return contextMenu; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TableViewDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.collections.FXCollections; 4 | import javafx.collections.ObservableList; 5 | import javafx.scene.control.TableColumn; 6 | import javafx.scene.control.TableView; 7 | import javafx.scene.control.cell.PropertyValueFactory; 8 | import javafx.scene.layout.Pane; 9 | import org.modernclients.ch3.Sample; 10 | import org.modernclients.ch3.model.Person; 11 | 12 | import java.util.function.Consumer; 13 | 14 | import static org.modernclients.ch3.model.Person.Gender.Female; 15 | import static org.modernclients.ch3.model.Person.Gender.Male; 16 | 17 | public class TableViewDemo implements Sample { 18 | 19 | @Override 20 | public void buildDemo(Pane container, Consumer console) { 21 | 22 | // Create the TableColumn instances 23 | final TableColumn firstNameColumn = new TableColumn<>("First Name"); 24 | final TableColumn lastNameColumn = new TableColumn<>("Last Name"); 25 | final TableColumn genderColumn = new TableColumn<>("Gender"); 26 | 27 | // Set data properties to columns 28 | firstNameColumn.setCellValueFactory(new PropertyValueFactory<>("firstName")); 29 | lastNameColumn.setCellValueFactory(new PropertyValueFactory<>("lastName")); 30 | genderColumn.setCellValueFactory(new PropertyValueFactory<>("gender")); 31 | 32 | // Create the ListView instance 33 | final TableView tableView = new TableView<>(); 34 | 35 | // Add TableColumns to TableView 36 | tableView.getColumns().addAll(firstNameColumn, lastNameColumn, genderColumn); 37 | 38 | // Add list of persons to TableView 39 | tableView.getItems().addAll(createPersons()); 40 | 41 | container.getChildren().add(tableView); 42 | } 43 | 44 | private ObservableList createPersons() { 45 | return FXCollections.observableArrayList( 46 | new Person("Jonathan", "Giles", Male), 47 | new Person("Julia", "Giles", Female), 48 | new Person("Henry", "Giles", Male), 49 | new Person("Pippa", "Giles", Female) 50 | ); 51 | } 52 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TreeTableViewDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.beans.property.ReadOnlyStringWrapper; 4 | import javafx.collections.ObservableList; 5 | import javafx.scene.control.TreeItem; 6 | import javafx.scene.control.TreeTableColumn; 7 | import javafx.scene.control.TreeTableView; 8 | import javafx.scene.layout.Pane; 9 | import org.modernclients.ch3.Sample; 10 | import org.modernclients.ch3.model.JavaFXNode; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.function.Consumer; 15 | 16 | /** 17 | * @author Abhinay Agarwal 18 | */ 19 | public class TreeTableViewDemo implements Sample { 20 | 21 | @Override 22 | public void buildDemo(Pane container, Consumer console) { 23 | 24 | List layoutList = Arrays.asList( 25 | new JavaFXNode("Pane", "Region"), 26 | new JavaFXNode("AnchorPane", "Pane"), 27 | new JavaFXNode("BorderPane", "Pane") 28 | ); 29 | 30 | List controlList = Arrays.asList( 31 | new JavaFXNode("Button", "ButtonBase"), 32 | new JavaFXNode("Label", "Labeled"), 33 | new JavaFXNode("ListView", "Control") 34 | ); 35 | 36 | TreeItem rootItem = new TreeItem<>(new JavaFXNode("JavaFX", "")); 37 | rootItem.setExpanded(true); 38 | 39 | TreeItem layouts = new TreeItem<>(new JavaFXNode("Layouts", "")); 40 | layoutList.forEach(item -> layouts.getChildren().addAll(new TreeItem<>(item))); 41 | 42 | TreeItem controls = new TreeItem<>(new JavaFXNode("Controls", "")); 43 | controlList.forEach(item -> controls.getChildren().addAll(new TreeItem<>(item))); 44 | 45 | rootItem.getChildren().addAll(layouts,controls); 46 | 47 | TreeTableColumn nameColumn = new TreeTableColumn<>("Name"); 48 | nameColumn.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue().getName())); 49 | nameColumn.setPrefWidth(150); 50 | TreeTableColumn parentColumn = new TreeTableColumn<>("Parent"); 51 | parentColumn.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue().getParent())); 52 | parentColumn.setPrefWidth(150); 53 | 54 | TreeTableView tree = new TreeTableView<>(rootItem); 55 | tree.setOnMouseClicked(e -> { 56 | ObservableList> selectedItems = tree.getSelectionModel().getSelectedItems(); 57 | if (selectedItems.size() > 0) { 58 | console.accept("Selected item -> " + selectedItems.get(0).getValue().getName()); 59 | } 60 | }); 61 | tree.getColumns().addAll(nameColumn, parentColumn); 62 | 63 | container.getChildren().add(tree); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/TreeViewDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.collections.ListChangeListener; 4 | import javafx.scene.control.Button; 5 | import javafx.scene.control.CheckBox; 6 | import javafx.scene.control.TreeCell; 7 | import javafx.scene.control.TreeItem; 8 | import javafx.scene.control.TreeView; 9 | import javafx.scene.layout.Pane; 10 | import org.modernclients.ch3.Sample; 11 | 12 | import java.util.function.Consumer; 13 | 14 | /** 15 | * @author Mohammad Hossein Rimaz 16 | * @author Frank Delporte 17 | */ 18 | public class TreeViewDemo implements Sample { 19 | private Consumer console; 20 | 21 | @Override 22 | public void buildDemo(Pane container, Consumer console) { 23 | this.console = console; 24 | 25 | TreeItem rootItem = new TreeItem<>("JavaFX"); 26 | rootItem.setExpanded(true); 27 | 28 | TreeItem treeItem1 = new TreeItem<>("Layouts"); 29 | TreeItem treeItem11 = new TreeItem<>("Pane"); 30 | TreeItem treeItem12 = new TreeItem<>("AnchorPane"); 31 | treeItem1.getChildren().addAll(treeItem11,treeItem12); 32 | 33 | TreeItem treeItem2 = new TreeItem<>("Controls"); 34 | TreeItem treeItem21 = new TreeItem<>("Button"); 35 | TreeItem treeItem22 = new TreeItem<>("CheckBox"); 36 | treeItem2.getChildren().addAll(treeItem21,treeItem22); 37 | 38 | rootItem.getChildren().addAll(treeItem1,treeItem2); 39 | 40 | TreeView tree = new TreeView<>(rootItem); 41 | tree.getSelectionModel().getSelectedItems().addListener((ListChangeListener>) c -> { 42 | if (c.next()) { 43 | console.accept("Tree View {\n" + 44 | " Removed Items from selection: " + c.getRemoved().toString() + 45 | "\n Added Items from selection: " + c.getAddedSubList().toString() + 46 | "\n}"); 47 | } 48 | }); 49 | 50 | // We set show root to false. This will hide the root and only show it's children in the treeview. 51 | tree.setShowRoot(false); 52 | tree.setCellFactory(e -> new CellControlRenderer()); 53 | 54 | container.getChildren().add(tree); 55 | } 56 | 57 | /** 58 | * Render a control depending on the content of the cell 59 | * Based on https://stackoverflow.com/questions/33360921/javafxhow-to-use-checkbox-and-button-in-treeview#33367482 60 | */ 61 | class CellControlRenderer extends TreeCell { 62 | @Override 63 | protected void updateItem(String item, boolean empty) { 64 | super.updateItem(item, empty); 65 | 66 | // If the cell is empty we don't show anything. 67 | if (isEmpty()) { 68 | setGraphic(null); 69 | setText(null); 70 | } else { 71 | // We only show the custom cell if it is a leaf, meaning it has no children. 72 | if (this.getTreeItem().isLeaf() && item.equalsIgnoreCase("button")) { 73 | Button button = new Button(item); 74 | setGraphic(button); 75 | setText(null); 76 | 77 | button.setOnAction(event -> console.accept("Button in the treeview was clicked")); 78 | } else if (this.getTreeItem().isLeaf() && item.equalsIgnoreCase("checkbox")) { 79 | CheckBox checkBox = new CheckBox(item); 80 | setGraphic(checkBox); 81 | setText(null); 82 | 83 | checkBox.setOnAction(event -> console.accept("The checkbox in the treeview changed to " + checkBox.isSelected())); 84 | } else { 85 | // If this is the root we just display the text. 86 | setGraphic(null); 87 | setText(item); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/AccordionDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.Accordion; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.CheckBox; 7 | import javafx.scene.control.Label; 8 | import javafx.scene.control.RadioButton; 9 | import javafx.scene.control.Separator; 10 | import javafx.scene.control.Slider; 11 | import javafx.scene.control.TitledPane; 12 | import javafx.scene.control.ToggleGroup; 13 | import javafx.scene.layout.Border; 14 | import javafx.scene.layout.BorderStroke; 15 | import javafx.scene.layout.BorderStrokeStyle; 16 | import javafx.scene.layout.BorderWidths; 17 | import javafx.scene.layout.CornerRadii; 18 | import javafx.scene.layout.HBox; 19 | import javafx.scene.layout.Pane; 20 | import javafx.scene.layout.VBox; 21 | import javafx.scene.paint.Color; 22 | 23 | import org.modernclients.ch3.Sample; 24 | 25 | import java.util.Optional; 26 | import java.util.function.Consumer; 27 | 28 | /** 29 | * @author Jonathan Giles 30 | * @author Frank Delporte 31 | */ 32 | public class AccordionDemo implements Sample { 33 | // Define the panes so we can use them later to change 34 | private TitledPane t1; 35 | private TitledPane t2; 36 | private TitledPane t3; 37 | private Accordion accordion; 38 | 39 | // Construct the demo screen 40 | @Override 41 | public void buildDemo(Pane container, Consumer console) { 42 | t1 = new TitledPane("TitledPane 1", new Button("Button 1")); 43 | t2 = new TitledPane("TitledPane 2", new Button("Button 2")); 44 | t3 = new TitledPane("TitledPane 3", new Button("Button 3")); 45 | 46 | accordion = new Accordion(); 47 | accordion.getPanes().addAll(t1, t2, t3); 48 | 49 | container.getChildren().addAll(accordion); 50 | } 51 | 52 | // Add the control panel 53 | @Override 54 | public Optional buildControlPanel() { 55 | // Create animation checkbox 56 | CheckBox animatedCheckBox = new CheckBox(); 57 | animatedCheckBox.setSelected(true); 58 | 59 | t1.animatedProperty().bind(animatedCheckBox.selectedProperty()); 60 | t2.animatedProperty().bind(animatedCheckBox.selectedProperty()); 61 | t3.animatedProperty().bind(animatedCheckBox.selectedProperty()); 62 | 63 | // Create radiobuttons 64 | RadioButton rbNone = new RadioButton(); 65 | rbNone.setSelected(true); 66 | 67 | RadioButton rb1 = new RadioButton(); 68 | RadioButton rb2 = new RadioButton(); 69 | RadioButton rb3 = new RadioButton(); 70 | 71 | // Create a toggle group and add all the radio buttons to it 72 | ToggleGroup group = new ToggleGroup(); 73 | group.getToggles().addAll(rbNone, rb1, rb2, rb3); 74 | 75 | group.selectedToggleProperty().addListener(o -> { 76 | t1.setBorder(Border.EMPTY); 77 | t2.setBorder(Border.EMPTY); 78 | t3.setBorder(Border.EMPTY); 79 | 80 | if (rb1.isSelected()) { 81 | t1.setBorder(new Border(new BorderStroke(Color.GREEN, BorderStrokeStyle.SOLID, new CornerRadii(10), new BorderWidths(3)))); 82 | accordion.setExpandedPane(t1); 83 | } else if (rb2.isSelected()) { 84 | t2.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.DASHED, new CornerRadii(0), new BorderWidths(1)))); 85 | accordion.setExpandedPane(t2); 86 | } else if (rb3.isSelected()) { 87 | t3.setBorder(new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.DOTTED, new CornerRadii(0), new BorderWidths(5)))); 88 | accordion.setExpandedPane(t3); 89 | } 90 | }); 91 | 92 | VBox vBox = new VBox(10, 93 | new HBox(10, animatedCheckBox, new Label("Animated")), 94 | new Separator(), 95 | new Label("Highlight"), 96 | new HBox(10, rbNone, new Label("None")), 97 | new HBox(10, rb1, new Label("Accordion 1")), 98 | new HBox(10, rb2, new Label("Accordion 2")), 99 | new HBox(10, rb3, new Label("Accordion 3")) 100 | ); 101 | return Optional.of(vBox); 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/DialogsDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.geometry.Pos; 4 | import javafx.scene.control.*; 5 | import javafx.scene.control.Alert.AlertType; 6 | import javafx.scene.layout.Pane; 7 | import javafx.scene.layout.VBox; 8 | import org.modernclients.ch3.Sample; 9 | 10 | import java.util.function.Consumer; 11 | 12 | /** 13 | * @author Almas Baimagambetov 14 | * @author Jonathan Giles 15 | */ 16 | public class DialogsDemo implements Sample { 17 | 18 | @Override 19 | public void buildDemo(Pane container, Consumer console) { 20 | VBox box = new VBox(10, 21 | createButton(new Alert(AlertType.INFORMATION), 22 | "Information Alert", "Provides the user with information"), 23 | 24 | createButton(new Alert(AlertType.CONFIRMATION), 25 | "Confirmation Alert", "Seeks confirmation from the user"), 26 | 27 | createButton(new Alert(AlertType.WARNING), 28 | "Warning Alert", "Warns the user about some fact or action"), 29 | 30 | createButton(new Alert(AlertType.ERROR), 31 | "Error Alert", "Suggests that something has gone wrong"), 32 | 33 | createButton(new ChoiceDialog<>("Cat", 34 | "Dog", "Cat", "Mouse"), 35 | "Choice Dialog", "Shows a list of choices to the user"), 36 | 37 | createButtonForBlockingDialog(new TextInputDialog("Hello World"), 38 | "Blocking Dialog", "Shows a text input control to the user", console), 39 | 40 | createButtonForCustomDialog(console) 41 | ); 42 | box.setAlignment(Pos.CENTER); 43 | 44 | container.getChildren().addAll(box); 45 | } 46 | 47 | private Button createButtonForBlockingDialog(Dialog dialog, String dialogName, String dialogText, Consumer console) { 48 | Button btn = createButton(dialog, dialogName, dialogText); 49 | btn.setOnAction(e -> { 50 | dialog.showAndWait() 51 | .ifPresent(result -> console.accept("Result is " + result)); 52 | }); 53 | return btn; 54 | } 55 | 56 | private Button createButtonForCustomDialog(Consumer console) { 57 | Dialog dialog = new Dialog<>(); 58 | 59 | TextField fieldUserName = new TextField(); 60 | PasswordField fieldPassword = new PasswordField(); 61 | 62 | Pane content = new VBox(5, 63 | new Label("Username:"), 64 | fieldUserName, 65 | new Label("Password:"), 66 | fieldPassword); 67 | 68 | DialogPane dialogPane = dialog.getDialogPane(); 69 | dialogPane.setHeaderText("Enter username and password..."); 70 | dialogPane.setContent(content); 71 | 72 | dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); 73 | 74 | dialog.setResultConverter(buttonType -> { 75 | // if the user pressed the OK button, return the credentials, otherwise 76 | // we return null 77 | if (buttonType == ButtonType.OK) { 78 | return new Credential(fieldUserName.getText(), fieldPassword.getText()); 79 | } 80 | 81 | return null; 82 | }); 83 | 84 | Button btn = createButton(dialog, "Custom Dialog", "Asks the user for credentials"); 85 | btn.setOnAction(e -> { 86 | dialog.showAndWait() 87 | .ifPresent(result -> console.accept("Username is " + result.username + ". Password is " + result.password)); 88 | }); 89 | return btn; 90 | } 91 | 92 | private Button createButton(Dialog dialog, String dialogName, String dialogText) { 93 | dialog.setContentText(dialogText); 94 | 95 | Button btn = new Button("Show " + dialogName); 96 | btn.setOnAction(e -> dialog.show()); 97 | return btn; 98 | } 99 | 100 | private static class Credential { 101 | private String username; 102 | private String password; 103 | 104 | public Credential(String username, String password) { 105 | this.username = username; 106 | this.password = password; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/ToolTipDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import java.util.Optional; 4 | import java.util.function.Consumer; 5 | 6 | import org.modernclients.ch3.Sample; 7 | 8 | import javafx.geometry.HPos; 9 | import javafx.geometry.Pos; 10 | import javafx.scene.Node; 11 | import javafx.scene.control.Button; 12 | import javafx.scene.control.Label; 13 | import javafx.scene.control.Spinner; 14 | import javafx.scene.control.ToggleButton; 15 | import javafx.scene.control.Tooltip; 16 | import javafx.scene.layout.GridPane; 17 | import javafx.scene.layout.Pane; 18 | import javafx.scene.paint.Color; 19 | import javafx.scene.shape.Circle; 20 | import javafx.scene.shape.Rectangle; 21 | import javafx.scene.text.Text; 22 | import javafx.util.Duration; 23 | 24 | /** 25 | * @author Cyril FISCHER 26 | */ 27 | public class ToolTipDemo implements Sample { 28 | 29 | private final Rectangle rectangle = new Rectangle(120, 120, Color.RED); 30 | private final Tooltip rectangleTooltip = new Tooltip("A Red Square (size : 120px)"); 31 | 32 | private final Button hoverButton = new Button("Hover over me"); 33 | private final Tooltip buttonTootlip = new Tooltip( 34 | "A button \n" + "Tooltip on control can be added with a convenient method"); 35 | 36 | private final Circle circle = new Circle(50, Color.BLUE); 37 | private final Tooltip circleTooltip = new Tooltip("A Blue Circle (radius : 50px)"); 38 | 39 | @Override 40 | public void buildDemo(Pane container, Consumer console) { 41 | 42 | installToolTips(); 43 | 44 | layoutDemo(rectangle, hoverButton, circle, container); 45 | } 46 | 47 | private void layoutDemo(Rectangle rectangle, Button hoverButton, Circle circle, Pane container) { 48 | 49 | Text instructionText = new Text("Hover over nodes"); 50 | instructionText.setStyle("-fx-font-size: 18;"); 51 | GridPane.setHalignment(instructionText, HPos.CENTER); 52 | 53 | GridPane gridPane = new GridPane(); 54 | gridPane.setAlignment(Pos.CENTER); 55 | gridPane.setStyle("-fx-hgap: 3em; -fx-vgap: 3em"); 56 | gridPane.add(instructionText, 0, 0, 3, 1); 57 | gridPane.add(rectangle, 0, 1); 58 | gridPane.add(hoverButton, 1, 1); 59 | gridPane.add(circle, 2, 1); 60 | container.getChildren().add(gridPane); 61 | 62 | } 63 | 64 | @Override 65 | public Optional buildControlPanel() { 66 | 67 | ToggleButton installToggle = new ToggleButton("Install/Uninstall"); 68 | installToggle.setSelected(true); 69 | installToggle.setOnAction(a -> { 70 | if (installToggle.isSelected()) { 71 | installToolTips(); 72 | } else { 73 | uninstallTooltips(); 74 | } 75 | }); 76 | 77 | Spinner showDelaySpinner = new Spinner<>(0, 10_000, 1000, 500); 78 | showDelaySpinner.valueProperty().addListener((obs, old, showDelay) -> setShowDelay(showDelay)); 79 | Label showDelayLabel = new Label("Showing Delay :"); 80 | 81 | Spinner hideDelaySpinner = new Spinner<>(0, 10_000, 200, 500); 82 | hideDelaySpinner.valueProperty().addListener((obs, old, hideDelay) -> setHideDelay(hideDelay)); 83 | Label hideDelayLabel = new Label("Hiding Delay :"); 84 | 85 | Spinner showDurationSpinner = new Spinner<>(0, 10_000, 5000, 500); 86 | showDurationSpinner.valueProperty().addListener((obs, old, showDuration) -> setshowDuration(showDuration)); 87 | Label showDurationLabel = new Label("Duration :"); 88 | 89 | GridPane gridPane = layoutControlPanel(installToggle, showDelaySpinner, showDelayLabel, hideDelaySpinner, 90 | hideDelayLabel, showDurationSpinner, showDurationLabel); 91 | return Optional.of(gridPane); 92 | } 93 | 94 | private GridPane layoutControlPanel(ToggleButton installToggle, Spinner showDelaySpinner, 95 | Label showDelayLabel, Spinner hideDelaySpinner, Label hideDelayLabel, 96 | Spinner showDurationSpinner, Label showDurationLabel) { 97 | GridPane gridPane = new GridPane(); 98 | gridPane.add(installToggle, 0, 0); 99 | 100 | gridPane.add(showDelayLabel, 0, 1); 101 | gridPane.add(showDelaySpinner, 1, 1); 102 | 103 | gridPane.add(hideDelayLabel, 0, 2); 104 | gridPane.add(hideDelaySpinner, 1, 2); 105 | 106 | gridPane.add(showDurationLabel, 0, 3); 107 | gridPane.add(showDurationSpinner, 1, 3); 108 | 109 | gridPane.setAlignment(Pos.TOP_CENTER); 110 | gridPane.setStyle("-fx-hgap: 1em; -fx-vgap: 1em"); 111 | return gridPane; 112 | } 113 | 114 | private void setShowDelay(int showDelay) { 115 | Duration duration = new Duration(showDelay); 116 | rectangleTooltip.setShowDelay(duration); 117 | buttonTootlip.setShowDelay(duration); 118 | circleTooltip.setShowDelay(duration); 119 | } 120 | 121 | private void setHideDelay(int hideDelay) { 122 | Duration duration = new Duration(hideDelay); 123 | rectangleTooltip.setHideDelay(duration); 124 | buttonTootlip.setHideDelay(duration); 125 | circleTooltip.setHideDelay(duration); 126 | 127 | } 128 | 129 | private void setshowDuration(int showDuration) { 130 | Duration duration = new Duration(showDuration); 131 | rectangleTooltip.setShowDuration(duration); 132 | buttonTootlip.setShowDuration(duration); 133 | circleTooltip.setShowDuration(duration); 134 | 135 | } 136 | 137 | private void installToolTips() { 138 | Tooltip.install(rectangle, rectangleTooltip); 139 | hoverButton.setTooltip(buttonTootlip); 140 | Tooltip.install(circle, circleTooltip); 141 | } 142 | 143 | private void uninstallTooltips() { 144 | Tooltip.uninstall(rectangle, rectangleTooltip); 145 | hoverButton.setTooltip(null); 146 | Tooltip.uninstall(circle, circleTooltip); 147 | 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/DemoApp.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3; 2 | 3 | import javafx.application.Application; 4 | import javafx.geometry.Insets; 5 | import javafx.scene.Scene; 6 | import javafx.scene.control.ListCell; 7 | import javafx.scene.control.ListView; 8 | import javafx.scene.control.TextArea; 9 | import javafx.scene.layout.*; 10 | import javafx.stage.Stage; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.util.*; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.Stream; 17 | 18 | /** 19 | * @author Jonathan Giles 20 | */ 21 | public class DemoApp extends Application { 22 | 23 | private List samples; 24 | 25 | public static void main(String[] args) { 26 | launch(args); 27 | } 28 | 29 | @Override public void start(Stage primaryStage) { 30 | samples = getClasses("org.modernclients.ch3.samples") 31 | .filter(Sample.class::isAssignableFrom) 32 | .map(cls -> createSample((Class)cls)) 33 | .filter(Optional::isPresent) 34 | .map(Optional::get) 35 | .sorted() 36 | .collect(Collectors.toList()); 37 | 38 | // simple UI to show demos - listview on left, demo area in center (with optional control panel area), console output at bottom 39 | StackPane demoPane = new StackPane(); 40 | demoPane.getStyleClass().add("demo-pane"); 41 | 42 | StackPane controlPane = new StackPane(); 43 | controlPane.getStyleClass().addAll("control-pane"); 44 | controlPane.setManaged(false); 45 | 46 | TextArea console = new TextArea(); 47 | console.setPrefRowCount(10); 48 | console.getStyleClass().add("console"); 49 | 50 | ListView samplesList = new ListView<>(); 51 | samplesList.getStyleClass().add("samples-list"); 52 | samplesList.getItems().addAll(samples); 53 | samplesList.setCellFactory(listView -> new ListCell() { 54 | @Override protected void updateItem(Sample item, boolean empty) { 55 | super.updateItem(item, empty); 56 | if (empty) { 57 | setText(""); 58 | } else { 59 | setText(item.getName()); 60 | } 61 | } 62 | }); 63 | samplesList.getSelectionModel().selectedItemProperty().addListener((o, oldSample, newSample) -> { 64 | // when selection changes, update the demo area 65 | demoPane.getChildren().clear(); 66 | newSample.buildDemo(demoPane, str -> console.setText(str + "\r\n" + console.getText())); 67 | 68 | controlPane.getChildren().clear(); 69 | newSample.buildControlPanel().ifPresent(controlPane.getChildren()::add); 70 | 71 | // show control pane? 72 | boolean showControlPane = !controlPane.getChildren().isEmpty(); 73 | controlPane.setManaged(showControlPane); 74 | controlPane.setVisible(showControlPane); 75 | 76 | console.clear(); 77 | }); 78 | 79 | GridPane gridPane = new GridPane(); 80 | gridPane.add(samplesList, 0, 0, 1, 2); 81 | gridPane.add(demoPane, 1, 0, 1, 1); 82 | gridPane.add(controlPane, 2, 0, 1, 1); 83 | gridPane.add(console, 1, 1, 2, 1); 84 | 85 | GridPane.setVgrow(demoPane, Priority.ALWAYS); 86 | GridPane.setHgrow(demoPane, Priority.ALWAYS); 87 | GridPane.setHgrow(console, Priority.ALWAYS); 88 | 89 | GridPane.setMargin(samplesList, new Insets(10)); 90 | GridPane.setMargin(demoPane, new Insets(10, 10, 0, 0)); 91 | GridPane.setMargin(controlPane, new Insets(10, 10, 0, 0)); 92 | GridPane.setMargin(console, new Insets(10, 10, 10, 0)); 93 | 94 | Scene scene = new Scene(gridPane, 1400, 900); 95 | scene.getStylesheets().add(DemoApp.class.getResource("ch3styles.css").toExternalForm()); 96 | primaryStage.setScene(scene); 97 | primaryStage.setTitle("Chapter 3 UI Controls Samples"); 98 | primaryStage.show(); 99 | } 100 | 101 | private Optional createSample(Class cls) { 102 | try { 103 | return Optional.of(cls.getConstructor().newInstance()); 104 | } catch (Exception e) { 105 | e.printStackTrace(); 106 | return Optional.empty(); 107 | } 108 | } 109 | 110 | /** 111 | * Scans all classes accessible from the context class loader which belong to the given package and subpackages. 112 | */ 113 | private static Stream> getClasses(final String packageName) { 114 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 115 | String path = packageName.replace('.', '/'); 116 | 117 | try { 118 | return Collections.list(classLoader.getResources(path)).stream() 119 | .map(url -> new File(url.getFile())) 120 | .flatMap(dir -> findClasses(dir, packageName)); 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | return Stream.empty(); 124 | } 125 | } 126 | /** 127 | * Recursive method used to find all classes in a given directory and subdirs. 128 | */ 129 | private static Stream> findClasses(File directory, String packageName) { 130 | if (!directory.exists()) { 131 | return Stream.empty(); 132 | } 133 | 134 | return Stream.of(directory.listFiles()).flatMap(file -> { 135 | try { 136 | if (file.isDirectory()) { 137 | return findClasses(file, packageName + "." + file.getName()); 138 | } else if (file.getName().endsWith(".class")) { 139 | return Stream.of(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); 140 | } 141 | } catch (ClassNotFoundException e) { 142 | e.printStackTrace(); 143 | } 144 | return Stream.empty(); 145 | }); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/DatePickerDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.scene.Node; 4 | import javafx.scene.control.Button; 5 | import javafx.scene.control.CheckBox; 6 | import javafx.scene.control.DateCell; 7 | import javafx.scene.control.DatePicker; 8 | import javafx.scene.layout.Pane; 9 | import javafx.scene.layout.VBox; 10 | import javafx.util.Callback; 11 | import javafx.util.StringConverter; 12 | import org.modernclients.ch3.Sample; 13 | 14 | import java.time.DateTimeException; 15 | import java.time.LocalDate; 16 | import java.time.chrono.HijrahChronology; 17 | import java.time.chrono.IsoChronology; 18 | import java.time.format.DateTimeFormatter; 19 | import java.util.Optional; 20 | import java.util.function.Consumer; 21 | import java.util.function.Predicate; 22 | 23 | /** 24 | * @author Fouad Almalki 25 | */ 26 | public class DatePickerDemo implements Sample { 27 | 28 | private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); 29 | 30 | private DatePicker datePicker; 31 | private boolean disableRangeSelection; 32 | private Predicate dateValidator = localDate -> { 33 | if(disableRangeSelection) { 34 | return localDate != null && !localDate.isAfter(LocalDate.now()); 35 | } 36 | else return localDate != null; 37 | }; 38 | 39 | @Override 40 | public void buildDemo(Pane container, Consumer console) { 41 | datePicker = new DatePicker(); 42 | datePicker.setChronology(IsoChronology.INSTANCE); 43 | datePicker.setOnAction(e -> { 44 | LocalDate date = datePicker.getValue(); 45 | console.accept("Selected date: " + (date != null ? dateFormatter.format(date) : null)); 46 | }); 47 | 48 | Callback dayCellFactory = dp -> new DateCell() { 49 | @Override 50 | public void updateItem(LocalDate date, boolean empty) { 51 | super.updateItem(date, empty); 52 | 53 | if(!dateValidator.test(date)) { 54 | setDisable(true); 55 | } 56 | } 57 | }; 58 | datePicker.setDayCellFactory(dayCellFactory); 59 | 60 | StringConverter converter = new StringConverter() { 61 | @Override 62 | public String toString(LocalDate date) { 63 | if(date != null) return dateFormatter.format(date); 64 | else return ""; 65 | } 66 | 67 | @Override 68 | public LocalDate fromString(String string) { 69 | if(string != null && !string.trim().isEmpty()) { 70 | 71 | LocalDate oldValue = datePicker.getValue(); 72 | LocalDate newValue; 73 | 74 | try { 75 | newValue = LocalDate.parse(string, dateFormatter); 76 | } 77 | catch(DateTimeException e) { 78 | console.accept("The text \"" + string + "\" does not match the pattern \"dd/MM/yyyy\""); 79 | return oldValue; 80 | } 81 | 82 | if(!dateValidator.test(newValue)) { 83 | console.accept("The date (" + dateFormatter.format(newValue) + ") is not allowed!"); 84 | return oldValue; 85 | } 86 | else return newValue; 87 | } 88 | else return null; 89 | } 90 | }; 91 | datePicker.setConverter(converter); 92 | 93 | container.getChildren().addAll(datePicker); 94 | } 95 | 96 | @Override 97 | public Optional buildControlPanel() { 98 | CheckBox cbShowPromptText = new CheckBox("Show prompt text (dd/MM/yyyy)"); 99 | cbShowPromptText.selectedProperty().addListener((observable, oldValue, newValue) -> { 100 | if(newValue) { // selected 101 | datePicker.setPromptText("dd/MM/yyyy"); 102 | } 103 | else datePicker.setPromptText(""); 104 | }); 105 | cbShowPromptText.setSelected(true); 106 | 107 | CheckBox cbShowWeekNumbers = new CheckBox("Show week numbers"); 108 | cbShowWeekNumbers.selectedProperty().addListener((observable, oldValue, newValue) -> 109 | datePicker.setShowWeekNumbers(newValue)); 110 | 111 | CheckBox cbShowHijrahCalendar = new CheckBox("Show hijrah calendar"); 112 | cbShowHijrahCalendar.selectedProperty().addListener((observable, oldValue, newValue) -> { 113 | if(newValue) { // selected 114 | datePicker.setChronology(HijrahChronology.INSTANCE); 115 | } 116 | else datePicker.setChronology(IsoChronology.INSTANCE); 117 | }); 118 | 119 | CheckBox cbDisableTextEditing = new CheckBox("Disable text editing"); 120 | cbDisableTextEditing.selectedProperty().addListener((observable, oldValue, newValue) -> 121 | datePicker.getEditor().setEditable(!newValue)); 122 | 123 | CheckBox cbDisableRangeSelection = new CheckBox("Disable range selection (e.g. future dates)"); 124 | cbDisableRangeSelection.selectedProperty().addListener((observable, oldValue, newValue) -> { 125 | disableRangeSelection = newValue; 126 | 127 | if(!dateValidator.test(datePicker.getValue())) { 128 | datePicker.setValue(null); 129 | } 130 | }); 131 | 132 | Button btnToday = new Button("Today"); 133 | btnToday.setOnAction(event -> datePicker.setValue(LocalDate.now())); 134 | 135 | VBox vBox = new VBox(cbShowPromptText, cbShowWeekNumbers, cbShowHijrahCalendar, 136 | cbDisableTextEditing, cbDisableRangeSelection, btnToday); 137 | vBox.setSpacing(5.0); 138 | return Optional.of(vBox); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/org/modernclients/ch3/samples/SpinnerDemo.java: -------------------------------------------------------------------------------- 1 | package org.modernclients.ch3.samples; 2 | 3 | import javafx.collections.FXCollections; 4 | import javafx.collections.ObservableList; 5 | import javafx.geometry.Insets; 6 | import javafx.geometry.NodeOrientation; 7 | import javafx.scene.Node; 8 | import javafx.scene.control.*; 9 | import javafx.scene.layout.GridPane; 10 | import javafx.scene.layout.Pane; 11 | import org.modernclients.ch3.Sample; 12 | 13 | import java.util.Optional; 14 | import java.util.function.Consumer; 15 | 16 | /** 17 | * @author Jonathan Giles 18 | */ 19 | public class SpinnerDemo implements Sample { 20 | 21 | private Spinner spinner; 22 | 23 | @Override 24 | public void buildDemo(Pane container, Consumer console) { 25 | spinner = new Spinner(); 26 | 27 | // debug output to console 28 | spinner.valueProperty().addListener((o, oldValue, newValue) -> 29 | System.out.println("value changed: '" + oldValue + "' -> '" + newValue + "'")); 30 | spinner.getEditor().textProperty().addListener((o, oldValue, newValue) -> 31 | System.out.println("text changed: '" + oldValue + "' -> '" + newValue + "'")); 32 | 33 | // add spinner to table 34 | container.getChildren().add(spinner); 35 | } 36 | 37 | @Override 38 | public Optional buildControlPanel() { 39 | // this lets us switch between the spinner value factories 40 | ComboBox spinnerValueFactoryOptions = 41 | new ComboBox<>(FXCollections.observableArrayList("Integer", "Double", "List")); 42 | spinnerValueFactoryOptions.getSelectionModel().selectedItemProperty().addListener((o, oldValue, newValue) -> { 43 | if (newValue == null) return; 44 | 45 | switch (newValue) { 46 | default: 47 | case "Integer": { 48 | spinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(5, 10)); 49 | break; 50 | } 51 | 52 | case "List": { 53 | ObservableList items = FXCollections.observableArrayList("Jonathan", "Julia", "Henry", "Pippa"); 54 | spinner.setValueFactory(new SpinnerValueFactory.ListSpinnerValueFactory<>(items)); 55 | break; 56 | } 57 | 58 | case "Double": { 59 | spinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 1.0, 0.5, 0.05)); 60 | break; 61 | } 62 | } 63 | }); 64 | spinnerValueFactoryOptions.getSelectionModel().select(0); 65 | 66 | ComboBox spinnerStyleClassOptions = 67 | new ComboBox<>(FXCollections.observableArrayList( 68 | "Default (Arrows on right (Vertical))", 69 | "Arrows on right (Horizontal)", 70 | "Arrows on left (Vertical)", 71 | "Arrows on left (Horizontal)", 72 | "Split (Vertical)", 73 | "Split (Horizontal)")); 74 | spinnerStyleClassOptions.getSelectionModel().selectedItemProperty().addListener((o, oldValue, newValue) -> { 75 | spinner.getStyleClass().removeAll( 76 | Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL, 77 | Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL, 78 | Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL, 79 | Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL, 80 | Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL); 81 | 82 | switch (newValue) { 83 | default: 84 | case "Default (Arrows on right (Vertical))": break; 85 | 86 | case "Arrows on right (Horizontal)": { 87 | spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL); 88 | break; 89 | } 90 | 91 | case "Arrows on left (Vertical)": { 92 | spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL); 93 | break; 94 | } 95 | 96 | case "Arrows on left (Horizontal)": { 97 | spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL); 98 | break; 99 | } 100 | 101 | case "Split (Vertical)": { 102 | spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL); 103 | break; 104 | } 105 | 106 | case "Split (Horizontal)": { 107 | spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL); 108 | break; 109 | } 110 | } 111 | }); 112 | spinnerStyleClassOptions.getSelectionModel().select(0); 113 | 114 | final CheckBox wrapAroundCheckBox = new CheckBox(); 115 | wrapAroundCheckBox.selectedProperty().addListener((o, oldValue, newValue) -> 116 | spinner.getValueFactory().setWrapAround(newValue)); 117 | 118 | final CheckBox editableCheckBox = new CheckBox(); 119 | spinner.editableProperty().bind(editableCheckBox.selectedProperty()); 120 | 121 | final CheckBox rtlCheckBox = new CheckBox(); 122 | rtlCheckBox.selectedProperty().addListener((o, oldValue, newValue) -> 123 | spinner.setNodeOrientation(newValue ? NodeOrientation.RIGHT_TO_LEFT : NodeOrientation.INHERIT)); 124 | 125 | 126 | 127 | GridPane grid = new GridPane(); 128 | grid.setHgap(10); 129 | grid.setVgap(10); 130 | grid.setPadding(new Insets(10)); 131 | 132 | int row = 0; 133 | 134 | grid.add(new Label("Value Factory:"), 0, row); 135 | grid.add(spinnerValueFactoryOptions, 1, row++); 136 | 137 | grid.add(new Label("Style Class:"), 0, row); 138 | grid.add(spinnerStyleClassOptions, 1, row++); 139 | 140 | grid.add(new Label("Wrap around:"), 0, row); 141 | grid.add(wrapAroundCheckBox, 1, row++); 142 | 143 | grid.add(new Label("Editable:"), 0, row); 144 | grid.add(editableCheckBox, 1, row++); 145 | 146 | grid.add(new Label("Right-to-left:"), 0, row); 147 | grid.add(rtlCheckBox, 1, row++); 148 | 149 | return Optional.of(grid); 150 | } 151 | } 152 | --------------------------------------------------------------------------------