JAVAFX 2.0
Practical Experience Building Rich Clients
Richard Bair & Jasper Potts
General
Binding
Controls
& Charts
AnimationThreading
CSS
Tips
 
 Tricks
General
Binding
Controls
 Charts
AnimationThreading
CSS
Node subnode = parentNode.lookup(“......”);
where .... is a CSS selector
Lets you quickly and easily get any descendent node.
Useful Selectors:
“#NodeID” find descendent node with id “NodeID”
“.StyleClass”
“ClassName”
LOOKUP
public class Lookup extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
final SplitPane splitPane = new SplitPane();
splitPane.getItems().addAll(
RegionBuilder.create().style(
-fx-background-color: red;).build(),
RegionBuilder.create().style(
-fx-background-color: dodgerblue;).build()
);
Scene scene = new Scene(splitPane, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
}
public class Lookup extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
final SplitPane splitPane = new SplitPane();
splitPane.getItems().addAll(
RegionBuilder.create().style(-fx-background-color: red;).build(),
RegionBuilder.create().style(-fx-background-color: dodgerblue;).build()
);
Scene scene = new Scene(splitPane, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
Pane gripper = (Pane)splitPane.lookup(.horizontal-grabber);
gripper.getChildren().add(
VBoxBuilder.create().spacing(5).children(
ButtonBuilder.create().text()
.onAction(new EventHandlerActionEvent() {
public void handle(ActionEvent t) {
splitPane.setDividerPosition(0, 0);
}
}).build(),
// .... a second button here for 
).build()
);
splitPane.lookup(.split-pane-divider).setStyle(-fx-padding: 8px;);
}
}
General
Binding
Controls
 Charts
AnimationThreading
CSS
CSS COLORING CONTROLS
CSS COLORING CONTROLS
+
CSS COLORING CONTROLS
-fx-base: red;
+
CSS COLORING CONTROLS
-fx-base: red;
+
=
CSS COLORING CONTROLS
-fx-base: red;
+
=
public ToolBar createToolBar(String id) {
return ToolBarBuilder.create()
.id(id)
.items(
new Button(Button 1),
new Button(Button 2),
new Slider(),
new ChoiceBox(
FXCollections.observableArrayList(Font.getFamilies())),
new Button(Button 3)
).build();
}
CSS COLORING CONTROLS
Method for creating example ToolBar
public class DarkToolbar extends Application {
public static void main(String[] args) {
Application.launch(args);
}
public ToolBar createToolBar(String id) {.....}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(Colored Toolbars);
ToolBar standardToolbar = createToolBar(standard);
ToolBar darkToolbar = createToolBar(dark);
ToolBar blueToolbar = createToolBar(blue);
Scene scene = new Scene(
VBoxBuilder.create()
.spacing(10)
.padding(new Insets(10))
.children(standardToolbar, darkToolbar, blueToolbar)
.build()
);
scene.getStylesheets().add(
DarkToolbar.class.getResource(DarkToolbar.css).toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
#dark {
-fx-base: #333333;
}
#blue {
-fx-base: dodgerblue;
}
CSS COLORING CONTROLS
#dark {
-fx-base: #333333;
}
#blue {
-fx-base: dodgerblue;
}
CSS COLORING CONTROLS
Say you have some rounded content in a SplitPane like:
CSS HIDDEN SPLITTERS
And you want to make the split panes not draw a bar like:
public class HidingSplitPane extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(Hidden Splitter);
final SplitPane splitPane = SplitPaneBuilder.create()
.id(hiddenSplitter)
.items(
RegionBuilder.create().styleClass(rounded).build(),
RegionBuilder.create().styleClass(rounded).build(),
RegionBuilder.create().styleClass(rounded).build()
).dividerPositions(new double[]{0.33,0.66})
.build();
Scene scene = new Scene(splitPane, 300, 100);
scene.getStylesheets().add(HidingSplitPane.class
.getResource(HidingSplitPane.css).toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
.rounded {
-fx-border-color: dodgerblue;
-fx-border-width: 2px;
-fx-border-radius: 15px;
-fx-padding: 20px;
}
#hiddenSplitter {
-fx-background-color: null;
-fx-padding: 10px;
}
#hiddenSplitter *.split-pane-divider,
#hiddenSplitter *.vertical-grabber,
#hiddenSplitter *.horizontal-grabber {
-fx-background-color: null;
-fx-border-color: null;
-fx-padding: 5px;
}
CSS HIDDEN SPLITTERS
Scene scene = new Scene(
VBoxBuilder.create()
.spacing(10)
.padding(new Insets(10))
.children(
ButtonBuilder.create()
.text(Inset Text Button)
.id(button1).build(),
LabelBuilder.create()
.text(Label styled as bar)
.id(label1).build()
)
.build()
);
CSS INSET TEXT
Apple style inset text, eg:
#button1 Text, #label1 Text{
-fx-effect: dropshadow(
one-pass-box , white, 0, 0 , 0, 1);
}
CSS INSET TEXT
Add some simple CSS:
General
Binding
Controls
 Charts
AnimationThreading
CSS
ANIMATION CACHING
When animating objects with complex graphics such as large
screens of controls like a data form can be jerky. So what
you need to do is cache them while animating.
public void handle(ActionEvent t) {
ANIMATION CACHING
SequentialTransitionBuilder.create()
.node(tilePane)
.children(.......)
.build().play();
}
public void handle(ActionEvent t) {
ANIMATION CACHING
SequentialTransitionBuilder.create()
.node(tilePane)
.children(.......)
.onFinished(new EventHandlerActionEvent() {
public void handle(ActionEvent t) {
tilePane.setCache(false);
}
})
tilePane.setCache(true);
tilePane.setCacheHint(CacheHint.SPEED);
.build().play();
}
General
Binding
Controls
 Charts
AnimationThreading
CSS
BINDING
Using the low level binding API, you can do arbitrarily
interesting binding, such as creating complex messages
THE SETUP
StringBinding
• Listens to the TextField
• Computes the String to be
displayed in the Label
• Uses a SimpleDateFormat and
some Calendar’s to do the job
TextField
• Enter the text here
Label
• Just binds to a custom binding
General
Binding
Controls
 Charts
AnimationThreading
CSS
TASKS
Using aTask, ProgressIndicator, and Region you can
implement background tasks which block the UI, simply
SERVICE
Using a Service instead of aTask, you can easily create a
reusable Service for doing background work
General
Binding
Controls
 Charts
AnimationThreading
CSS
VALIDATORS
Using the scene graph and some CSS you can wrap any
control in order to handle custom validation
Has-a
THE SETUP
TextInputValidatorPane
• A layout container which wraps its content
• Listens to changes in the TextField and
handles validation
• Sets the style class to “.validation-error” or
“.validation-warning” when there are
validation problems
Validator
• Interface which takes a control and
produces aValidationResult
ValidationResult
• Has a message  validation result
type (Error,Warning, Normal)
CSS
• Styles make the background of the
text field change
TextField
• Just lives its life normal, doesn’t
have to do anything special
Styles
Creates
TABLE PLACE HOLDER
You can place any node in as a place holder on aTableView
and it will be shown when there is no data.
final TableView tableView = new TableView();
TABLE PLACE HOLDER
tableView.getColumns().addAll(
TableColumnBuilder.create()
.text(First)
.cellValueFactory(new PropertyValueFactory(firstName))
.build(),
TableColumnBuilder.create()
.text(Last)
.cellValueFactory(new PropertyValueFactory(lastName))
.build(),
TableColumnBuilder.create()
.text(Email)
.prefWidth(220)
.cellValueFactory(new PropertyValueFactory(email))
.build()
);
final TableView tableView = new TableView();
TABLE PLACE HOLDER
tableView.getColumns().addAll(
TableColumnBuilder.create()
.text(First)
.cellValueFactory(new PropertyValueFactory(firstName))
.build(),
TableColumnBuilder.create()
.text(Last)
.cellValueFactory(new PropertyValueFactory(lastName))
.build(),
TableColumnBuilder.create()
.text(Email)
.prefWidth(220)
.cellValueFactory(new PropertyValueFactory(email))
.build()
);
tableView.setPlaceholder(
ProgressIndicatorBuilder.create()
.maxWidth(100)
.maxHeight(100)
.build());
TABLE PLACE HOLDER
PauseTransitionBuilder.create()
.duration(Duration.seconds(5))
.onFinished(new EventHandlerActionEvent() {
public void handle(ActionEvent t) {
tableView.setItems(FXCollections.observableArrayList(
new Person(Jacob, Smith,
jacob.smith@example.com ),
new Person(Isabella, Johnson,
isabella.johnson@example.com ),
new Person(Ethan, Williams,
ethan.williams@example.com ),
new Person(Emma, Jones,
emma.jones@example.com ),
new Person(Michael, Brown,
michael.brown@example.com )
));
}
})
.build().play();
SUBMIT PROGRESS
It is nice to give the user some feedback while we are
responding to their action.A quick neat way to do this for
a form submission is to add a ProgressIndicator to the
submit button.
SUBMIT PROGRESS
public class SaveButtonProgressIndicator extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(Save Button ProgressIndicator);
try {
Parent root =
FXMLLoader.load(getClass().getResource(SalesForm.fxml));
primaryStage.setScene(new Scene(root));
primaryStage.show();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
SUBMIT PROGRESS
GridPane xmlns:fx=http://javafx.com/fxml
fx:controller=tipsandtricks.SalesForm fx:id=salesForm
hgap=15 vgap=12
paddingInsets top=10 right=10 bottom=10 left=10//padding
children
Label text=Quantity: GridPane.columnIndex=1 GridPane.rowIndex=1/
TextField fx:id=quanityTextField text=1 GridPane.columnIndex=2
GridPane.rowIndex=1/
HBox spacing=10 alignment=center_right GridPane.columnIndex=1
GridPane.rowIndex=2 GridPane.columnSpan=3
children
Button text=Cancel onAction=#cancelAction cancelButton=true
style=-fx-base: #AAAAAA;/
Button text=Save onAction=#saveAction defaultButton=true
style=-fx-base: #333333;/
/children
/HBox
/children
/GridPane
SUBMIT PROGRESS
public class SalesForm {
@FXML private void cancelAction(final ActionEvent event) {}
@FXML private void saveAction(final ActionEvent event) {
// put progress indicator in save button to show user
// something is happening
Button saveButton = (Button)event.getSource();
ProgressIndicator pi = new ProgressIndicator();
pi.setPrefSize(14,14);
saveButton.setGraphic(pi);
}
}
IMAGE BARCHART
You can customize the look of JavaFX charts with CSS
such as styling the bars of a BarChart with images.
IMAGE BARCHART
You can customize the look of JavaFX charts with CSS
such as styling the bars of a BarChart with images.
IMAGE BARCHART
public class ImageBarChart extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(Image BarChart);
BarChart barChart = new BarChart(new CategoryAxis(), new NumberAxis());
barChart.setLegendVisible(false);
barChart.getData().add(
new XYChart.SeriesString,Integer(Sales Per Product,
FXCollections.observableArrayList(
new XYChart.DataString, Integer(SUV,120),
new XYChart.DataString, Integer(Sedan,50),
new XYChart.DataString, Integer(Truck,180),
new XYChart.DataString, Integer(Van,20)
)
)
);
Scene scene = new Scene(barChart, 350, 300);
scene.getStylesheets().add(InsetText.class
.getResource(ImageBarChart.css).toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
IMAGE BARCHART
.chart {
-fx-background-color: -fx-box-border, #f5f5f5;
-fx-background-insets: 0, 1;
-fx-font-size: 0.9em;
}
.chart-bar {
-fx-background-color: rgba(0,168,355,0.05);
-fx-border-color: rgba(0,168,355,0.3) rgba(0,168,355,0.3)
transparent rgba(0,168,355,0.3);
-fx-background-radius: 0;
-fx-background-position: center bottom;
-fx-background-repeat: no-repeat space;
-fx-background-image: url(van-s.png);
}
.data0.chart-bar { -fx-background-image: url(suv-s.png); }
.data1.chart-bar { -fx-background-image: url(sedan-s.png); }
.data2.chart-bar { -fx-background-image: url(truck-s.png); }
.data3.chart-bar { -fx-background-image: url(van-2.png); }
DRILL DOWN CHART
You can attach mouse handling to items in a chart so you
can do drill down or other actions.
DRILL DOWN CHART
public class DrilldownChart extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(Drilldown Chart);
PieChart.Data A,B,C,D;
final PieChart pie = new PieChart(
FXCollections.observableArrayList(
A = new PieChart.Data(A, 20),
B = new PieChart.Data(B, 30),
C = new PieChart.Data(C, 10),
D = new PieChart.Data(D, 40)
)
);
Scene scene = new Scene(pie, 350, 300);
scene.getStylesheets().add(InsetText.class
.getResource(DrilldownChart.css).toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
DRILL DOWN CHART
public class DrilldownChart extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(Drilldown Chart);
PieChart.Data A,B,C,D;
final PieChart pie = new PieChart(
FXCollections.observableArrayList(
A = new PieChart.Data(A, 20),
B = new PieChart.Data(B, 30),
C = new PieChart.Data(C, 10),
D = new PieChart.Data(D, 40)
)
);
A.getNode().setOnMouseClicked(new EventHandlerMouseEvent() {
public void handle(MouseEvent t) {
pie.setData(FXCollections.observableArrayList(
new PieChart.Data(a1, 7),
new PieChart.Data(a2, 2),
new PieChart.Data(a3, 5),
new PieChart.Data(a4, 3),
new PieChart.Data(a5, 2)
));
}
});
Scene scene = new Scene(pie, 350, 300);
scene.getStylesheets().add(InsetText.class
.getResource(DrilldownChart.css).toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
DRILL DOWN CHART
.chart-pie:hover {
-fx-border-color: red;
-fx-border-width: 2px;
}
SEARCH BOX
You can combine standard controls + some CSS and
create new controls such as a search box.
SEARCH BOX
public class SearchBoxApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override public void start(Stage primaryStage) {
primaryStage.setTitle(SearchBox);
VBox root = new VBox();
root.getChildren().addAll(new SearchBox());
Scene scene = new Scene(root);
scene.getStylesheets().add(InsetText.class
.getResource(SearchBox.css).toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
SEARCH BOX
public class SearchBox extends Region {
private TextField textBox;
private Button clearButton;
public SearchBox() {
setId(SearchBox);
getStyleClass().add(search-box);
setMinHeight(24);
setPrefSize(150, 24);
setMaxHeight(24);
textBox = new TextField();
textBox.setPromptText(Search);
clearButton = new Button();
clearButton.setVisible(false);
getChildren().addAll(textBox, clearButton);
......
}
@Override protected void layoutChildren() {
textBox.resize(getWidth(),getHeight());
clearButton.resizeRelocate(getWidth()-18,6,12,13);
}
}
SEARCH BOX
public class SearchBox extends Region {
private TextField textBox;
private Button clearButton;
public SearchBox() {
setId(SearchBox);
getStyleClass().add(search-box);
setMinHeight(24);
setPrefSize(150, 24);
setMaxHeight(24);
textBox = new TextField();
textBox.setPromptText(Search);
clearButton = new Button();
clearButton.setVisible(false);
getChildren().addAll(textBox, clearButton);
clearButton.setOnAction(new EventHandlerActionEvent() {
@Override public void handle(ActionEvent actionEvent) {
textBox.setText();
textBox.requestFocus();
}
});
textBox.textProperty().addListener(new ChangeListenerString() {
@Override public void changed(ObservableValue? extends String
observable, String oldValue, String newValue) {
clearButton.setVisible(textBox.getText().length() != 0);
}
});
}
@Override protected void layoutChildren() {
textBox.resize(getWidth(),getHeight());
clearButton.resizeRelocate(getWidth()-18,6,12,13);
}
}
SEARCH BOX
.root {
-fx-padding: 10px;
-fx-background-image: url(images/top-bar.png);
-fx-background-size: cover;
-fx-background-position: left top;
-fx-background-repeat: no-repeat;
}
.search-box .text-field {
-fx-background-color: white;
-fx-background-insets: 1;
-fx-background-radius: 15;
-fx-padding: -9 5 -11 0;
-fx-border-image-source: url(images/search-box.png);
-fx-border-image-slice: 12 12 12 22 fill;
-fx-border-image-width: 12 12 12 22;
-fx-border-image-repeat: stretch;
-fx-font-size: 13px;
-fx-prompt-text-fill: grey;
}
.search-box .text-field:focused {
-fx-background-color: -fx-focus-color, white;
-fx-background-insets: -1.4, 1;
-fx-background-radius: 14.4;
}
SEARCH BOX
SEARCH BOX
.search-box .button {
-fx-background-color: null;
-fx-background-image: url(images/search-clear.png);
}
.search-box .button:hover {
-fx-background-image: url(images/search-clear-over.png);
}

Practical Experience Building JavaFX Rich Clients

  • 1.
    JAVAFX 2.0 Practical ExperienceBuilding Rich Clients Richard Bair & Jasper Potts
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
    Node subnode =parentNode.lookup(“......”); where .... is a CSS selector Lets you quickly and easily get any descendent node. Useful Selectors: “#NodeID” find descendent node with id “NodeID” “.StyleClass” “ClassName” LOOKUP
  • 7.
    public class Lookupextends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { final SplitPane splitPane = new SplitPane(); splitPane.getItems().addAll( RegionBuilder.create().style( -fx-background-color: red;).build(), RegionBuilder.create().style( -fx-background-color: dodgerblue;).build() ); Scene scene = new Scene(splitPane, 300, 250); primaryStage.setScene(scene); primaryStage.show(); } }
  • 8.
    public class Lookupextends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { final SplitPane splitPane = new SplitPane(); splitPane.getItems().addAll( RegionBuilder.create().style(-fx-background-color: red;).build(), RegionBuilder.create().style(-fx-background-color: dodgerblue;).build() ); Scene scene = new Scene(splitPane, 300, 250); primaryStage.setScene(scene); primaryStage.show(); Pane gripper = (Pane)splitPane.lookup(.horizontal-grabber); gripper.getChildren().add( VBoxBuilder.create().spacing(5).children( ButtonBuilder.create().text() .onAction(new EventHandlerActionEvent() { public void handle(ActionEvent t) { splitPane.setDividerPosition(0, 0); } }).build(), // .... a second button here for ).build() ); splitPane.lookup(.split-pane-divider).setStyle(-fx-padding: 8px;); } }
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
    public ToolBar createToolBar(Stringid) { return ToolBarBuilder.create() .id(id) .items( new Button(Button 1), new Button(Button 2), new Slider(), new ChoiceBox( FXCollections.observableArrayList(Font.getFamilies())), new Button(Button 3) ).build(); } CSS COLORING CONTROLS Method for creating example ToolBar
  • 17.
    public class DarkToolbarextends Application { public static void main(String[] args) { Application.launch(args); } public ToolBar createToolBar(String id) {.....} @Override public void start(Stage primaryStage) { primaryStage.setTitle(Colored Toolbars); ToolBar standardToolbar = createToolBar(standard); ToolBar darkToolbar = createToolBar(dark); ToolBar blueToolbar = createToolBar(blue); Scene scene = new Scene( VBoxBuilder.create() .spacing(10) .padding(new Insets(10)) .children(standardToolbar, darkToolbar, blueToolbar) .build() ); scene.getStylesheets().add( DarkToolbar.class.getResource(DarkToolbar.css).toString()); primaryStage.setScene(scene); primaryStage.show(); } }
  • 18.
    #dark { -fx-base: #333333; } #blue{ -fx-base: dodgerblue; } CSS COLORING CONTROLS
  • 19.
    #dark { -fx-base: #333333; } #blue{ -fx-base: dodgerblue; } CSS COLORING CONTROLS
  • 20.
    Say you havesome rounded content in a SplitPane like: CSS HIDDEN SPLITTERS And you want to make the split panes not draw a bar like:
  • 21.
    public class HidingSplitPaneextends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle(Hidden Splitter); final SplitPane splitPane = SplitPaneBuilder.create() .id(hiddenSplitter) .items( RegionBuilder.create().styleClass(rounded).build(), RegionBuilder.create().styleClass(rounded).build(), RegionBuilder.create().styleClass(rounded).build() ).dividerPositions(new double[]{0.33,0.66}) .build(); Scene scene = new Scene(splitPane, 300, 100); scene.getStylesheets().add(HidingSplitPane.class .getResource(HidingSplitPane.css).toString()); primaryStage.setScene(scene); primaryStage.show(); } }
  • 22.
    .rounded { -fx-border-color: dodgerblue; -fx-border-width:2px; -fx-border-radius: 15px; -fx-padding: 20px; } #hiddenSplitter { -fx-background-color: null; -fx-padding: 10px; } #hiddenSplitter *.split-pane-divider, #hiddenSplitter *.vertical-grabber, #hiddenSplitter *.horizontal-grabber { -fx-background-color: null; -fx-border-color: null; -fx-padding: 5px; } CSS HIDDEN SPLITTERS
  • 23.
    Scene scene =new Scene( VBoxBuilder.create() .spacing(10) .padding(new Insets(10)) .children( ButtonBuilder.create() .text(Inset Text Button) .id(button1).build(), LabelBuilder.create() .text(Label styled as bar) .id(label1).build() ) .build() ); CSS INSET TEXT Apple style inset text, eg:
  • 24.
    #button1 Text, #label1Text{ -fx-effect: dropshadow( one-pass-box , white, 0, 0 , 0, 1); } CSS INSET TEXT Add some simple CSS:
  • 25.
  • 26.
    ANIMATION CACHING When animatingobjects with complex graphics such as large screens of controls like a data form can be jerky. So what you need to do is cache them while animating.
  • 28.
    public void handle(ActionEventt) { ANIMATION CACHING SequentialTransitionBuilder.create() .node(tilePane) .children(.......) .build().play(); }
  • 29.
    public void handle(ActionEventt) { ANIMATION CACHING SequentialTransitionBuilder.create() .node(tilePane) .children(.......) .onFinished(new EventHandlerActionEvent() { public void handle(ActionEvent t) { tilePane.setCache(false); } }) tilePane.setCache(true); tilePane.setCacheHint(CacheHint.SPEED); .build().play(); }
  • 30.
  • 31.
    BINDING Using the lowlevel binding API, you can do arbitrarily interesting binding, such as creating complex messages
  • 32.
    THE SETUP StringBinding • Listensto the TextField • Computes the String to be displayed in the Label • Uses a SimpleDateFormat and some Calendar’s to do the job TextField • Enter the text here Label • Just binds to a custom binding
  • 34.
  • 35.
    TASKS Using aTask, ProgressIndicator,and Region you can implement background tasks which block the UI, simply
  • 37.
    SERVICE Using a Serviceinstead of aTask, you can easily create a reusable Service for doing background work
  • 39.
  • 40.
    VALIDATORS Using the scenegraph and some CSS you can wrap any control in order to handle custom validation
  • 41.
    Has-a THE SETUP TextInputValidatorPane • Alayout container which wraps its content • Listens to changes in the TextField and handles validation • Sets the style class to “.validation-error” or “.validation-warning” when there are validation problems Validator • Interface which takes a control and produces aValidationResult ValidationResult • Has a message validation result type (Error,Warning, Normal) CSS • Styles make the background of the text field change TextField • Just lives its life normal, doesn’t have to do anything special Styles Creates
  • 43.
    TABLE PLACE HOLDER Youcan place any node in as a place holder on aTableView and it will be shown when there is no data.
  • 45.
    final TableView tableView= new TableView(); TABLE PLACE HOLDER tableView.getColumns().addAll( TableColumnBuilder.create() .text(First) .cellValueFactory(new PropertyValueFactory(firstName)) .build(), TableColumnBuilder.create() .text(Last) .cellValueFactory(new PropertyValueFactory(lastName)) .build(), TableColumnBuilder.create() .text(Email) .prefWidth(220) .cellValueFactory(new PropertyValueFactory(email)) .build() );
  • 46.
    final TableView tableView= new TableView(); TABLE PLACE HOLDER tableView.getColumns().addAll( TableColumnBuilder.create() .text(First) .cellValueFactory(new PropertyValueFactory(firstName)) .build(), TableColumnBuilder.create() .text(Last) .cellValueFactory(new PropertyValueFactory(lastName)) .build(), TableColumnBuilder.create() .text(Email) .prefWidth(220) .cellValueFactory(new PropertyValueFactory(email)) .build() ); tableView.setPlaceholder( ProgressIndicatorBuilder.create() .maxWidth(100) .maxHeight(100) .build());
  • 47.
    TABLE PLACE HOLDER PauseTransitionBuilder.create() .duration(Duration.seconds(5)) .onFinished(newEventHandlerActionEvent() { public void handle(ActionEvent t) { tableView.setItems(FXCollections.observableArrayList( new Person(Jacob, Smith, jacob.smith@example.com ), new Person(Isabella, Johnson, isabella.johnson@example.com ), new Person(Ethan, Williams, ethan.williams@example.com ), new Person(Emma, Jones, emma.jones@example.com ), new Person(Michael, Brown, michael.brown@example.com ) )); } }) .build().play();
  • 48.
    SUBMIT PROGRESS It isnice to give the user some feedback while we are responding to their action.A quick neat way to do this for a form submission is to add a ProgressIndicator to the submit button.
  • 50.
    SUBMIT PROGRESS public classSaveButtonProgressIndicator extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle(Save Button ProgressIndicator); try { Parent root = FXMLLoader.load(getClass().getResource(SalesForm.fxml)); primaryStage.setScene(new Scene(root)); primaryStage.show(); } catch (IOException ex) { ex.printStackTrace(); } } }
  • 51.
    SUBMIT PROGRESS GridPane xmlns:fx=http://javafx.com/fxml fx:controller=tipsandtricks.SalesFormfx:id=salesForm hgap=15 vgap=12 paddingInsets top=10 right=10 bottom=10 left=10//padding children Label text=Quantity: GridPane.columnIndex=1 GridPane.rowIndex=1/ TextField fx:id=quanityTextField text=1 GridPane.columnIndex=2 GridPane.rowIndex=1/ HBox spacing=10 alignment=center_right GridPane.columnIndex=1 GridPane.rowIndex=2 GridPane.columnSpan=3 children Button text=Cancel onAction=#cancelAction cancelButton=true style=-fx-base: #AAAAAA;/ Button text=Save onAction=#saveAction defaultButton=true style=-fx-base: #333333;/ /children /HBox /children /GridPane
  • 52.
    SUBMIT PROGRESS public classSalesForm { @FXML private void cancelAction(final ActionEvent event) {} @FXML private void saveAction(final ActionEvent event) { // put progress indicator in save button to show user // something is happening Button saveButton = (Button)event.getSource(); ProgressIndicator pi = new ProgressIndicator(); pi.setPrefSize(14,14); saveButton.setGraphic(pi); } }
  • 53.
    IMAGE BARCHART You cancustomize the look of JavaFX charts with CSS such as styling the bars of a BarChart with images.
  • 54.
    IMAGE BARCHART You cancustomize the look of JavaFX charts with CSS such as styling the bars of a BarChart with images.
  • 56.
    IMAGE BARCHART public classImageBarChart extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle(Image BarChart); BarChart barChart = new BarChart(new CategoryAxis(), new NumberAxis()); barChart.setLegendVisible(false); barChart.getData().add( new XYChart.SeriesString,Integer(Sales Per Product, FXCollections.observableArrayList( new XYChart.DataString, Integer(SUV,120), new XYChart.DataString, Integer(Sedan,50), new XYChart.DataString, Integer(Truck,180), new XYChart.DataString, Integer(Van,20) ) ) ); Scene scene = new Scene(barChart, 350, 300); scene.getStylesheets().add(InsetText.class .getResource(ImageBarChart.css).toString()); primaryStage.setScene(scene); primaryStage.show(); } }
  • 57.
    IMAGE BARCHART .chart { -fx-background-color:-fx-box-border, #f5f5f5; -fx-background-insets: 0, 1; -fx-font-size: 0.9em; } .chart-bar { -fx-background-color: rgba(0,168,355,0.05); -fx-border-color: rgba(0,168,355,0.3) rgba(0,168,355,0.3) transparent rgba(0,168,355,0.3); -fx-background-radius: 0; -fx-background-position: center bottom; -fx-background-repeat: no-repeat space; -fx-background-image: url(van-s.png); } .data0.chart-bar { -fx-background-image: url(suv-s.png); } .data1.chart-bar { -fx-background-image: url(sedan-s.png); } .data2.chart-bar { -fx-background-image: url(truck-s.png); } .data3.chart-bar { -fx-background-image: url(van-2.png); }
  • 58.
    DRILL DOWN CHART Youcan attach mouse handling to items in a chart so you can do drill down or other actions.
  • 60.
    DRILL DOWN CHART publicclass DrilldownChart extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle(Drilldown Chart); PieChart.Data A,B,C,D; final PieChart pie = new PieChart( FXCollections.observableArrayList( A = new PieChart.Data(A, 20), B = new PieChart.Data(B, 30), C = new PieChart.Data(C, 10), D = new PieChart.Data(D, 40) ) ); Scene scene = new Scene(pie, 350, 300); scene.getStylesheets().add(InsetText.class .getResource(DrilldownChart.css).toString()); primaryStage.setScene(scene); primaryStage.show(); } }
  • 61.
    DRILL DOWN CHART publicclass DrilldownChart extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle(Drilldown Chart); PieChart.Data A,B,C,D; final PieChart pie = new PieChart( FXCollections.observableArrayList( A = new PieChart.Data(A, 20), B = new PieChart.Data(B, 30), C = new PieChart.Data(C, 10), D = new PieChart.Data(D, 40) ) ); A.getNode().setOnMouseClicked(new EventHandlerMouseEvent() { public void handle(MouseEvent t) { pie.setData(FXCollections.observableArrayList( new PieChart.Data(a1, 7), new PieChart.Data(a2, 2), new PieChart.Data(a3, 5), new PieChart.Data(a4, 3), new PieChart.Data(a5, 2) )); } }); Scene scene = new Scene(pie, 350, 300); scene.getStylesheets().add(InsetText.class .getResource(DrilldownChart.css).toString()); primaryStage.setScene(scene); primaryStage.show(); } }
  • 62.
    DRILL DOWN CHART .chart-pie:hover{ -fx-border-color: red; -fx-border-width: 2px; }
  • 63.
    SEARCH BOX You cancombine standard controls + some CSS and create new controls such as a search box.
  • 65.
    SEARCH BOX public classSearchBoxApp extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle(SearchBox); VBox root = new VBox(); root.getChildren().addAll(new SearchBox()); Scene scene = new Scene(root); scene.getStylesheets().add(InsetText.class .getResource(SearchBox.css).toString()); primaryStage.setScene(scene); primaryStage.show(); } }
  • 66.
    SEARCH BOX public classSearchBox extends Region { private TextField textBox; private Button clearButton; public SearchBox() { setId(SearchBox); getStyleClass().add(search-box); setMinHeight(24); setPrefSize(150, 24); setMaxHeight(24); textBox = new TextField(); textBox.setPromptText(Search); clearButton = new Button(); clearButton.setVisible(false); getChildren().addAll(textBox, clearButton); ...... } @Override protected void layoutChildren() { textBox.resize(getWidth(),getHeight()); clearButton.resizeRelocate(getWidth()-18,6,12,13); } }
  • 67.
    SEARCH BOX public classSearchBox extends Region { private TextField textBox; private Button clearButton; public SearchBox() { setId(SearchBox); getStyleClass().add(search-box); setMinHeight(24); setPrefSize(150, 24); setMaxHeight(24); textBox = new TextField(); textBox.setPromptText(Search); clearButton = new Button(); clearButton.setVisible(false); getChildren().addAll(textBox, clearButton); clearButton.setOnAction(new EventHandlerActionEvent() { @Override public void handle(ActionEvent actionEvent) { textBox.setText(); textBox.requestFocus(); } }); textBox.textProperty().addListener(new ChangeListenerString() { @Override public void changed(ObservableValue? extends String observable, String oldValue, String newValue) { clearButton.setVisible(textBox.getText().length() != 0); } }); } @Override protected void layoutChildren() { textBox.resize(getWidth(),getHeight()); clearButton.resizeRelocate(getWidth()-18,6,12,13); } }
  • 68.
    SEARCH BOX .root { -fx-padding:10px; -fx-background-image: url(images/top-bar.png); -fx-background-size: cover; -fx-background-position: left top; -fx-background-repeat: no-repeat; }
  • 69.
    .search-box .text-field { -fx-background-color:white; -fx-background-insets: 1; -fx-background-radius: 15; -fx-padding: -9 5 -11 0; -fx-border-image-source: url(images/search-box.png); -fx-border-image-slice: 12 12 12 22 fill; -fx-border-image-width: 12 12 12 22; -fx-border-image-repeat: stretch; -fx-font-size: 13px; -fx-prompt-text-fill: grey; } .search-box .text-field:focused { -fx-background-color: -fx-focus-color, white; -fx-background-insets: -1.4, 1; -fx-background-radius: 14.4; } SEARCH BOX
  • 70.
    SEARCH BOX .search-box .button{ -fx-background-color: null; -fx-background-image: url(images/search-clear.png); } .search-box .button:hover { -fx-background-image: url(images/search-clear-over.png); }