Hướng dẫn và ví dụ JavaFX TreeTableView
1. JavaFX TreeTableView
JavaFX cung cấp cho bạn class TreeTableView, nó được sử dụng cùng với TreeItem, TreeTableColumn và TreeTableCell giúp bạn hiển thị dữ liệu dưới dạng bảng (Tabular) đồng thời dưới dạng cây. Bạn có thể xem hình minh họa dưới đây:
Giống với TableView bạn có thể tạo ra các cột lồng nhau. Để tạo một TreeTableView bạn cần:
- Thêm các TreeItem vào TreeTableView để có được một cấu trúc cây.
- Định nghĩa các cột của bảng.
- Định nghĩa cách hiển thị dữ liệu trên mỗi ô thông qua phương thức TreeTableColumn.setCellValueFactory.
2. Ví dụ với TreeTableView
Tạo một đối tượng TreeTableView và thêm các cột (TreeTableColumn).
TreeTableView<Employee> treeTableView = new TreeTableView<Employee>();
// Tạo cột EmpNo (Kiểu dữ liệu String)
TreeTableColumn<Employee, String> empNoCol //
= new TreeTableColumn<Employee, String>("Emp No");
.....
// Thêm các cột vào TreeTable
treeTableView.getColumns().addAll(empNoCol, fullNameCol,
positionCol, genderCol, singleCol);
Tạo các TreeItem và thêm vào TreeTableView để có một cấu trúc cây:
// Thêm dữ liệu
Employee empBoss = new Employee("E00", "Abc@gmail.com", //
"Boss", "Boss", "Manager", "M", false);
Employee empSmith = new Employee("E01", "Smith@gmail.com", //
"Susan", "Smith", "Salesman", "F", true);
Employee empMcNeil = new Employee("E02", "McNeil@gmail.com", //
"Anne", "McNeil", "Cleck", "M", false);
// Phần tử gốc
TreeItem<Employee> itemRoot = new TreeItem<Employee>(empBoss);
TreeItem<Employee> itemSmith = new TreeItem<Employee>(empSmith);
TreeItem<Employee> itemMcNeil = new TreeItem<Employee>(empMcNeil);
itemRoot.getChildren().addAll(itemSmith, itemMcNeil);
// Sét đặt phần tử gốc cho cây.
treeTableView.setRoot(itemRoot);
Định nghĩa cách hiển thị dữ liệu trên mỗi ô của cây.
// Định nghĩa cách để lấy dữ liệu cho mỗi ô.
// Lấy giá trị từ các thuộc tính của Employee.
empNoCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("empNo"));
firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("firstName"));
lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("lastName"));
positionCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("position"));
genderCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("gender"));
singleCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, Boolean>("single"));
Xem ví dụ đầy đủ:
TreeTableViewDemo.java
package org.o7planning.javafx.treetableview;
import org.o7planning.javafx.model.Employee;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TreeTableViewDemo extends Application {
@Override
public void start(Stage stage) {
TreeTableView<Employee> treeTableView = new TreeTableView<Employee>();
// Tạo cột EmpNo (Kiểu dữ liệu String)
TreeTableColumn<Employee, String> empNoCol //
= new TreeTableColumn<Employee, String>("Emp No");
// Tạo cột FullName (Kiểu dữ liệu String)
TreeTableColumn<Employee, String> fullNameCol//
= new TreeTableColumn<Employee, String>("Full Name");
// Tạo 2 cột con cho cột FullName
TreeTableColumn<Employee, String> firstNameCol //
= new TreeTableColumn<Employee, String>("First Name");
TreeTableColumn<Employee, String> lastNameCol //
= new TreeTableColumn<Employee, String>("Last Name");
// Thêm 2 cột con vào cột FullName
fullNameCol.getColumns().addAll(firstNameCol, lastNameCol);
// Gender Column
TreeTableColumn<Employee, String> genderCol //
= new TreeTableColumn<Employee, String>("Gender");
// Position Column
TreeTableColumn<Employee, String> positionCol //
= new TreeTableColumn<Employee, String>("Position");
// Single? Column
TreeTableColumn<Employee, Boolean> singleCol//
= new TreeTableColumn<Employee, Boolean>("Single?");
// Định nghĩa cách để lấy dữ liệu cho mỗi ô.
// Lấy giá trị từ các thuộc tính của Employee.
empNoCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("empNo"));
firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("firstName"));
lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("lastName"));
positionCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("position"));
genderCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("gender"));
singleCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, Boolean>("single"));
// Thêm các cột vào TreeTable
treeTableView.getColumns().addAll(empNoCol, fullNameCol,positionCol, genderCol, singleCol);
// Thêm dữ liệu
Employee empBoss = new Employee("E00", "Abc@gmail.com", //
"Boss", "Boss", "Manager", "M", false);
Employee empSmith = new Employee("E01", "Smith@gmail.com", //
"Susan", "Smith", "Salesman", "F", true);
Employee empMcNeil = new Employee("E02", "McNeil@gmail.com", //
"Anne", "McNeil", "Cleck", "M", false);
// Phần tử gốc
TreeItem<Employee> itemRoot = new TreeItem<Employee>(empBoss);
TreeItem<Employee> itemSmith = new TreeItem<Employee>(empSmith);
TreeItem<Employee> itemMcNeil = new TreeItem<Employee>(empMcNeil);
itemRoot.getChildren().addAll(itemSmith, itemMcNeil);
treeTableView.setRoot(itemRoot);
//
StackPane root = new StackPane();
root.setPadding(new Insets(5));
root.getChildren().add(treeTableView);
stage.setTitle("TreeTableView (o7planning.org)");
Scene scene = new Scene(root, 450, 300);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Employee.java
package org.o7planning.javafx.model;
public class Employee {
private String empNo;
private String firstName;
private String lastName;
private String email;
private String position;
private String gender;
private boolean single;
public Employee(String empNo, String email, //
String firstName, String lastName, String position, String gender, boolean single) {
this.empNo = empNo;
this.email = email;
this.firstName = firstName;
this.lastName = lastName;
this.position = position;
this.gender = gender;
this.single = single;
}
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public boolean isSingle() {
return single;
}
public void setSingle(boolean single) {
this.single = single;
}
}
3. Sửa dữ liệu trên TreeTableView
Bạn có thể hiệu chỉnh trực tiếp trên TreeTableView, dữ liệu sẽ được update vào Model. Hình ảnh dưới đây minh họa một TreeTableView có thể hiệu chỉnh.
setCellFactory & setCellValueFactory
treeTableColumn.setCellValueFactory
- Là phương thức sét đặt cách để lấy dữ liệu, mà dữ liệu đó sẽ hiển thị trên 1 ô của TreeTableView.
- Là phương thức sét đặt cách vẽ ra (render) một điều khiển (Controls) khi người dùng đang sửa dữ liệu trên 1 ô.
onCellEditComit
Tiếp theo bạn cần định nghĩa ra cách mà dữ liệu mới sẽ được cập nhập vào Model, bằng cách sử dụng phương thức treeTableColumn.setOnEditCommit. Sau khi người dùng hiệu chỉnh xong ô trên TreeTableView dữ liệu mới sẽ được cập nhập vào Model.
Với các ô hiển thị CheckBox trên TreeTableView:Lưu ý rằng các CheckBoxTreeTableCell vẽ ra (render) CheckBox 'sống', có nghĩa là các CheckBox là luôn luôn tương tác và có thể chọn hoặc bỏ chọn trực tiếp bởi người sử dụng. Điều này có nghĩa rằng nó không phải là cần thiết chuyển sang trạng thái hiệu chỉnh của ô (thường để chuyển trạng thái hiệu chỉnh ô người dùng kích đúp vào ô). Một tác dụng phụ của việc này là các callbacks chỉnh sửa thông thường (chẳng hạn như onCommitEdit) sẽ không được gọi. Nếu bạn muốn được thông báo về những thay đổi, bạn nên làm việc với các bộ quan sát (Observe) thuộc tính boolean được chế tác bởi các CheckBox.
Ví dụ đầy đủ:
TreeTableViewEditDemo.java
package org.o7planning.javafx.treetableview;
import org.o7planning.javafx.model.Employee;
import org.o7planning.javafx.model.Gender;
import javafx.application.Application;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.CheckBoxTreeTableCell;
import javafx.scene.control.cell.ComboBoxTreeTableCell;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TreeTableViewEditDemo extends Application {
@Override
public void start(Stage stage) {
TreeTableView<Employee> treeTableView = new TreeTableView<Employee>();
treeTableView.setEditable(true);
// Tạo cột EmpNo (Kiểu dữ liệu String)
TreeTableColumn<Employee, String> empNoCol //
= new TreeTableColumn<Employee, String>("Emp No");
// Tạo cột FullName (Kiểu dữ liệu String)
TreeTableColumn<Employee, String> fullNameCol//
= new TreeTableColumn<Employee, String>("Full Name");
// Tạo 2 cột con cho cột FullName
TreeTableColumn<Employee, String> firstNameCol //
= new TreeTableColumn<Employee, String>("First Name");
TreeTableColumn<Employee, String> lastNameCol //
= new TreeTableColumn<Employee, String>("Last Name");
// Thêm 2 cột con vào cột FullName
fullNameCol.getColumns().addAll(firstNameCol, lastNameCol);
// Gender Column
TreeTableColumn<Employee, Gender> genderCol //
= new TreeTableColumn<Employee, Gender>("Gender");
genderCol.setMinWidth(90);
// Position Column
TreeTableColumn<Employee, String> positionCol //
= new TreeTableColumn<Employee, String>("Position");
// Single? Column
TreeTableColumn<Employee, Boolean> singleCol//
= new TreeTableColumn<Employee, Boolean>("Single?");
// Thêm các cột vào TreeTable
treeTableView.getColumns().addAll(empNoCol, fullNameCol, positionCol, genderCol, singleCol);
// Thêm dữ liệu
Employee empBoss = new Employee("E00", "Abc@gmail.com", //
"Boss", "Boss", "Manager", "M", false);
Employee empSmith = new Employee("E01", "Smith@gmail.com", //
"Susan", "Smith", "Salesman", "F", true);
Employee empMcNeil = new Employee("E02", "McNeil@gmail.com", //
"Anne", "McNeil", "Cleck", "M", false);
// Phần tử gốc
TreeItem<Employee> itemRoot = new TreeItem<Employee>(empBoss);
TreeItem<Employee> itemSmith = new TreeItem<Employee>(empSmith);
TreeItem<Employee> itemMcNeil = new TreeItem<Employee>(empMcNeil);
itemRoot.getChildren().addAll(itemSmith, itemMcNeil);
treeTableView.setRoot(itemRoot);
// Định nghĩa cách để lấy dữ liệu cho mỗi ô.
// Lấy giá trị từ các thuộc tính của Employee.
empNoCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("empNo"));
firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("firstName"));
lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("lastName"));
positionCol.setCellValueFactory(new TreeItemPropertyValueFactory<Employee, String>("position"));
// GENDER (COMBO BOX).
genderCol.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<Employee, Gender>, //
ObservableValue<Gender>>() {
@Override
public ObservableValue<Gender> call(TreeTableColumn.CellDataFeatures<Employee, Gender> param) {
TreeItem<Employee> treeItem = param.getValue();
Employee emp = treeItem.getValue();
// F,M
String genderCode = emp.getGender();
Gender gender = Gender.getByCode(genderCode);
return new SimpleObjectProperty<Gender>(gender);
}
});
ObservableList<Gender> genderList = FXCollections.observableArrayList(//
Gender.values());
genderCol.setCellFactory(ComboBoxTreeTableCell.forTreeTableColumn(genderList));
// Sau khi người dùng sửa dữ liệu trên ô cần update vào Model.
genderCol.setOnEditCommit(new EventHandler<TreeTableColumn.CellEditEvent<Employee, Gender>>() {
@Override
public void handle(TreeTableColumn.CellEditEvent<Employee, Gender> event) {
TreeItem<Employee> item = event.getRowValue();
Employee emp = item.getValue();
Gender newGender = event.getNewValue();
emp.setGender(newGender.getCode());
System.out.println("Single column commit. new gender:" +newGender);
System.out.println("EMP:"+emp.isSingle());
}
});
// ==== SINGLE? (CHECH BOX) ===
singleCol.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<Employee, Boolean>, //
ObservableValue<Boolean>>() {
@Override
public ObservableValue<Boolean> call(TreeTableColumn.CellDataFeatures<Employee, Boolean> param) {
TreeItem<Employee> treeItem = param.getValue();
Employee emp = treeItem.getValue();
SimpleBooleanProperty booleanProp= new SimpleBooleanProperty(emp.isSingle());
// Chú ý: singleCol.setOnEditCommit(): Không làm việc với
// CheckBoxTreeTableCell.
// Khi cột "Single?" thay đổi
booleanProp.addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
Boolean newValue) {
emp.setSingle(newValue);
}
});
return booleanProp;
}
});
singleCol.setCellFactory(new Callback<TreeTableColumn<Employee,Boolean>,TreeTableCell<Employee,Boolean>>() {
@Override
public TreeTableCell<Employee,Boolean> call( TreeTableColumn<Employee,Boolean> p ) {
CheckBoxTreeTableCell<Employee,Boolean> cell = new CheckBoxTreeTableCell<Employee,Boolean>();
cell.setAlignment(Pos.CENTER);
return cell;
}
});
//
StackPane root = new StackPane();
root.setPadding(new Insets(5));
root.getChildren().add(treeTableView);
stage.setTitle("TreeTableView (o7planning.org)");
Scene scene = new Scene(root, 450, 300);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Gender.java
package org.o7planning.javafx.model;
public enum Gender {
FEMALE("F", "Famale"), MALE("M", "Male");
private String code;
private String text;
private Gender(String code, String text) {
this.code = code;
this.text = text;
}
public String getCode() {
return code;
}
public String getText() {
return text;
}
public static Gender getByCode(String genderCode) {
for (Gender g : Gender.values()) {
if (g.code.equals(genderCode)) {
return g;
}
}
return null;
}
@Override
public String toString() {
return this.text;
}
}
Các hướng dẫn lập trình JavaFX
- Mở một cửa sổ (window) mới trong JavaFX
- Hướng dẫn và ví dụ JavaFX ChoiceDialog
- Hướng dẫn và ví dụ JavaFX Alert Dialog
- Hướng dẫn và ví dụ JavaFX TextInputDialog
- Cài đặt e(fx)clipse cho Eclipse (Bộ công cụ lập trình JavaFX)
- Cài đặt JavaFX Scene Builder cho Eclipse
- Hướng dẫn lập trình JavaFX cho người mới bắt đầu - Hello JavaFX
- Hướng dẫn và ví dụ JavaFX FlowPane Layout
- Hướng dẫn và ví dụ JavaFX TilePane Layout
- Hướng dẫn và ví dụ JavaFX HBox, VBox Layout
- Hướng dẫn và ví dụ JavaFX BorderPane Layout
- Hướng dẫn và ví dụ JavaFX AnchorPane Layout
- Hướng dẫn và ví dụ JavaFX TitledPane
- Hướng dẫn và ví dụ JavaFX Accordion
- Hướng dẫn và ví dụ JavaFX ListView
- Hướng dẫn và ví dụ JavaFX Group
- Hướng dẫn và ví dụ JavaFX ComboBox
- Hướng dẫn sử dụng các phép biến hình (Transformations) trong JavaFX
- Các hiệu ứng (effects) trong JavaFX
- Hướng dẫn và ví dụ JavaFX GridPane Layout
- Hướng dẫn và ví dụ JavaFX StackPane Layout
- Hướng dẫn và ví dụ JavaFX ScrollPane
- Hướng dẫn và ví dụ JavaFX WebView và WebEngine
- Hướng dẫn và ví dụ JavaFX HTMLEditor
- Hướng dẫn và ví dụ JavaFX TableView
- Hướng dẫn và ví dụ JavaFX TreeView
- Hướng dẫn và ví dụ JavaFX TreeTableView
- Hướng dẫn và ví dụ JavaFX Menu
- Hướng dẫn và ví dụ JavaFX ContextMenu
- Hướng dẫn và ví dụ JavaFX Image và ImageView
- Hướng dẫn và ví dụ JavaFX Label
- Hướng dẫn và ví dụ JavaFX Hyperlink
- Hướng dẫn và ví dụ JavaFX Button
- Hướng dẫn và ví dụ JavaFX ToggleButton
- Hướng dẫn và ví dụ JavaFX RadioButton
- Hướng dẫn và ví dụ JavaFX MenuButton và SplitMenuButton
- Hướng dẫn và ví dụ JavaFX TextField
- Hướng dẫn và ví dụ JavaFX PasswordField
- Hướng dẫn và ví dụ JavaFX TextArea
- Hướng dẫn và ví dụ JavaFX Slider
- Hướng dẫn và ví dụ JavaFX Spinner
- Hướng dẫn và ví dụ JavaFX ProgressBar và ProgressIndicator
- Hướng dẫn và ví dụ JavaFX ChoiceBox
- Hướng dẫn và ví dụ JavaFX Tooltip
- Hướng dẫn và ví dụ JavaFX DatePicker
- Hướng dẫn và ví dụ JavaFX ColorPicker
- Hướng dẫn và ví dụ JavaFX FileChooser và DirectoryChooser
- Hướng dẫn và ví dụ JavaFX PieChart
- Hướng dẫn và ví dụ JavaFX AreaChart và StackedAreaChart
- Hướng dẫn và ví dụ JavaFX BarChart và StackedBarChart
- Hướng dẫn và ví dụ JavaFX Line
- Hướng dẫn và ví dụ JavaFX Rectangle và Ellipse
Show More