Permalink
Browse files

Added tableview article

1 parent 36a8fb0 commit 30d02e1f0d8c025d397ef73166d6f41d659c0cd0 @bekwam bekwam committed Dec 31, 2016
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -644,4 +644,218 @@ public class FilterListApp extends Application {
public String toString() { return playerName + " (" + team + ")"; }
}
}
+----
+
+== TableView
+Author: Carl Walker
+
+For JavaFX business applications, the `TableView` is an essential control. Use a `TableView` when you need to present multiple records in a flat row/column structure. This example shows the basic elements of a `TableView` and demonstrates the power of the component when JavaFX Binding is applied.
+
+The demonstration app is a `TableView` and a pair of Buttons. The `TableView` has four TableColumns: SKU, Item, Price, Tax. The `TableView` shows three objects in three rows: Mechanical Keyboard, Product Docs, O-Rings. The following screenshot shows the app immediately after startup.
+
+image::images/ui-controls/tableviewselectapp_screenshot.png[title="Intial View of Demo App"]
+
+The disabled logic of the Buttons is based on the selections in the `TableView`. Initially, no items are selected so both Buttons are disabled. If any item is selected -- the first item in the following screenshot -- the Inventory `Button` is enabled. The Tax `Button` is also enabled although that requires consulting the Tax value.
+
+image::images/ui-controls/tableviewselectapp_screenshot_selected_tax.png[title="With Taxable Item Selected"]
+
+If the Tax value for the selected item is false, then the Tax `Button` will be disabled. This screenshot shows the second item selected. The Inventory `Button` is enabled but the Tax `Button` is not.
+
+image::images/ui-controls/tableviewselectapp_screenshot_selected_notax.png[title="A Non-Taxable Item Disables the Tax Button"]
+
+=== Model and Declarations
+
+A `TableView` is based on a model which is a POJO called Item.
+
+[source,java]
+.Item.java
+----
+public class Item {
+
+ private final String sku;
+ private final String descr;
+ private final Float price;
+ private final Boolean taxable;
+
+ public Item(String sku, String descr, Float price, Boolean taxable) {
+ this.sku = sku;
+ this.descr = descr;
+ this.price = price;
+ this.taxable = taxable;
+ }
+
+ public String getSku() {
+ return sku;
+ }
+
+ public String getDescr() {
+ return descr;
+ }
+
+ public Float getPrice() {
+ return price;
+ }
+
+ public Boolean getTaxable() {
+ return taxable;
+ }
+}
+----
+
+The `TableView` and `TableColumn` use generics in their declarations. For `TableView`, the type parameter is Item. For the TableColumns, the type parameters are Item and the field type. The constructor of `TableColumn` accepts a column name. In this example, the column names diverge slightly from the actual field names.
+
+[source,java]
+.TableSelectApp.java
+----
+ TableView<Item> tblItems = new TableView<>();
+
+ TableColumn<Item, String> colSKU = new TableColumn<>("SKU");
+ TableColumn<Item, String> colDescr = new TableColumn<>("Item");
+ TableColumn<Item, Float> colPrice = new TableColumn<>("Price");
+ TableColumn<Item, Boolean> colTaxable = new TableColumn<>("Tax");
+
+ tblItems.getColumns().addAll(
+ colSKU, colDescr, colPrice, colTaxable
+ );
+----
+
+Adding model items to the `TableView` is done by adding items to the underlying collection.
+
+[source,java]
+.TableSelectApp.java
+----
+ tblItems.getItems().addAll(
+ new Item("KBD-0455892", "Mechanical Keyboard", 100.0f, true),
+ new Item( "145256", "Product Docs", 0.0f, false ),
+ new Item( "OR-198975", "O-Ring (100)", 10.0f, true)
+ );
+----
+
+At this point, the `TableView` has been configured and test data has been added. However, if you were to view the program, you would see three empty rows. That is because JavaFX is missing the linkage between the POJO and the TableColumns. That linkage is added to the TableColumns using a cellValueFactory.
+
+[source,java]
+.TableSelectApp.java
+----
+ colSKU.setCellValueFactory( new PropertyValueFactory<>("sku") );
+ colDescr.setCellValueFactory( new PropertyValueFactory<>("descr") );
+ colPrice.setCellValueFactory( new PropertyValueFactory<>("price") );
+ colTaxable.setCellValueFactory( new PropertyValueFactory<>("taxable") );
+----
+
+Viewing the program at this point will display the data in the appropriate columns.
+
+=== Selection
+
+To retrieve the selected item or items in a `TableView`, use the separate selectionModel object. Calling tblItems.getSelectionModel() returns an object that includes a property "selectedItem". This can be retrieved and used in a method, say to bring up an edit details screen. Alternatively, getSelectionModel() can return a JavaFX property "selectedItemProperty" for binding expressions.
+
+In the demo app, two Buttons are bound to the selectionModel of the `TableView`. Without binding, you might add listeners that examine the selection and make a call like setDisabled() on a Button. Prior to the `TableView` selection, you would also need initialization logic to handle the case where there is no selection. The binding syntax expresses this logic in a declarative statement that can handle both the listener and the initialization in a single line.
+
+[source,java]
+.TableSelectApp.java
+----
+ Button btnInventory = new Button("Inventory");
+ Button btnCalcTax = new Button("Tax");
+
+ btnInventory.disableProperty().bind(
+ tblItems.getSelectionModel().selectedItemProperty().isNull() <1>
+ );
+----
+
+<1> See "Ignoring Warnings for Null Select Binding Expressions" under "Best Practices" to show how to turn off warning messages when using this construct
+
+The btnInventory disable property will be true if there is no item selected (isNull()). When the screen is first displayed, no selection is made and the `Button` is disabled. Once any selection is made, btnInventory is enabled (disable=false).
+
+the btnCalcTax logic is slightly more complex. btnCalcTax too is disabled when there is no selection. However, btnCalcTax will also consider the contents of the selectedItem. A composite binding or() is used to join these two conditions. As before, there is an isNull() expression for no selection. The Bindings.select() checks the value of Item.taxable. A true taxable Item will enable btnCalcTax while a false item will disable the `Button`.
+
+[source,java]
+.TableSelectApp.java
+----
+ btnCalcTax.disableProperty().bind(
+ tblItems.getSelectionModel().selectedItemProperty().isNull().or(
+ Bindings.select(
+ tblItems.getSelectionModel().selectedItemProperty(),
+ "taxable"
+ ).isEqualTo(false)
+ )
+ );
+----
+
+Bindings.select() is the mechanism to extract a field from an object. selectedItemProperty() is the changing selectedItem and "taxable" is the single-hop path to the taxable field.
+
+This example showed how to set up a `TableView` based on a POJO. It also featured a pair of powerful binding expressions that allow you to link related controls without writing extra listeners and initialization code. The `TableView` is an indispensable control for the JavaFX business applications developer. It will be the best and most familiar control for displaying a list of structured items.
+
+=== Complete Code
+
+The complete code for the application follows. It is a pair of class files TableSelectApp.java and Item.java. Item.java was already presented in its entirety in an earlier section.
+
+[source,java]
+.TableSelectApp.java
+----
+public class TableSelectApp extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+
+ TableView<Item> tblItems = new TableView<>();
+ tblItems.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+
+ VBox.setVgrow(tblItems, Priority.ALWAYS );
+
+ TableColumn<Item, String> colSKU = new TableColumn<>("SKU");
+ TableColumn<Item, String> colDescr = new TableColumn<>("Item");
+ TableColumn<Item, Float> colPrice = new TableColumn<>("Price");
+ TableColumn<Item, Boolean> colTaxable = new TableColumn<>("Tax");
+
+ colSKU.setCellValueFactory( new PropertyValueFactory<>("sku") );
+ colDescr.setCellValueFactory( new PropertyValueFactory<>("descr") );
+ colPrice.setCellValueFactory( new PropertyValueFactory<>("price") );
+ colTaxable.setCellValueFactory( new PropertyValueFactory<>("taxable") );
+
+ tblItems.getColumns().addAll(
+ colSKU, colDescr, colPrice, colTaxable
+ );
+
+ tblItems.getItems().addAll(
+ new Item("KBD-0455892", "Mechanical Keyboard", 100.0f, true),
+ new Item( "145256", "Product Docs", 0.0f, false ),
+ new Item( "OR-198975", "O-Ring (100)", 10.0f, true)
+ );
+
+ Button btnInventory = new Button("Inventory");
+ Button btnCalcTax = new Button("Tax");
+
+ btnInventory.disableProperty().bind(
+ tblItems.getSelectionModel().selectedItemProperty().isNull()
+ );
+
+ btnCalcTax.disableProperty().bind(
+ tblItems.getSelectionModel().selectedItemProperty().isNull().or(
+ Bindings.select(
+ tblItems.getSelectionModel().selectedItemProperty(),
+ "taxable"
+ ).isEqualTo(false)
+ )
+ );
+
+ HBox buttonHBox = new HBox( btnInventory, btnCalcTax );
+ buttonHBox.setSpacing( 8 );
+
+ VBox vbox = new VBox( tblItems, buttonHBox );
+ vbox.setPadding( new Insets(10) );
+ vbox.setSpacing( 10 );
+
+ Scene scene = new Scene(vbox);
+
+ primaryStage.setTitle("TableSelectApp");
+ primaryStage.setScene( scene );
+ primaryStage.setHeight( 376 );
+ primaryStage.setWidth( 667 );
+ primaryStage.show();
+ }
+
+ public static void main(String[] args) {
+
+ launch(args);
+ }
+}
----

0 comments on commit 30d02e1

Please sign in to comment.