TableView 不显示ObservableList 对象的内容
我有两个几乎相似的自定义类用于存储简单的字符串数据 – 它们被称为“患者”和“跟踪”。它们彼此之间的区别仅在于已定义字段的数量。 两者的构造函数如下所示(使用getVariablesNames()
静态方法):
public class Patient { String patientID; String firstName; String lastName; String gender; String dateOfBirth; String age; String email; String phoneNumber; String city; public Patient(String patientID, String firstName, String lastName, String gender, String dateOfBirth, String age, String email, String phoneNumber, String city) { this.patientID = patientID; this.firstName = firstName; this.lastName = lastName; this.gender = gender; this.dateOfBirth = dateOfBirth; this.age = age; this.email = email; this.phoneNumber = phoneNumber; this.city = city; } public static String[] getVariablesNames() { Field[] fields = Patient.class.getDeclaredFields(); String[] variablesNames = new String[fields.length]; for (int i = 0; i < fields.length; i++) { variablesNames[i] = fields[i].getName(); } return variablesNames; } public String getPatientID() { return patientID; } public void setPatientID(String value) { patientID = value; } public String getFirstName() { return firstName; } public void setFirstName(String value) { firstName = value; } public String getLastName() { return lastName; } public void setLastName(String value) { lastName = value; } public String getGender() { return gender; } public void setGender(String value) { gender = value; } public String getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(String value) { dateOfBirth = value; } public String getAge() { return age; } public void setAge(String value) { age = value; } public String getEmail() { return email; } public void setEmail(String value) { email = value; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String value) { phoneNumber = value; } public String getCity() { return city; } public void setCity(String value) { city = value; } }
和“Trace”类的构造函数:
public class Trace { String action; String status; String message; String time; public Trace(String action, String status, String message, String time) { this.action = action; this.status = status; this.message = message; this.time = time; } public static String[] getVariablesNames() { Field[] fields = Trace.class.getDeclaredFields(); String[] variablesNames = new String[fields.length]; for (int i = 0; i < fields.length; i++) { variablesNames[i] = fields[i].getName(); } return variablesNames; } public void setActionText(String value) { action = value; } public String getActionText() { return action; } public void setStatusText(String value) { status = value; } public String getStatusText() { return status; } public void setMessageText(String value) { message = value; } public String getMessageText() { return message; } public void setTimeText(String value) { time = value; } public String getTimeText() { return time; } }
我使用这些类的对象来填充自定义TableView
实例,其中可以是“Patient”或“Trace”。 我遇到的问题是“Trace”对象值没有显示在表中,其中“Patient”类的对象没有问题。 自定义
TableView
类如下所示:
import javafx.collections.ObservableList; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; public class TableViewCustom extends TableView { public TableViewCustom(String[] columnNames, String[] variablesNames, ObservableList data) { super(); @SuppressWarnings("unchecked") TableColumn[] tableColumns = new TableColumn[variablesNames.length]; for (int i = 0; i < tableColumns.length; i++) { tableColumns[i] = new TableColumn(columnNames[i]); tableColumns[i].setCellValueFactory(new PropertyValueFactory(variablesNames[i])); } this.setItems(data); this.getColumns().addAll(tableColumns); this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); } }
以及使用“Patient”和“Trace”对象的此自定义TableView的示例实现:
import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.layout.BorderPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Demo extends Application { public Parent createContent() { /* layout */ BorderPane layout = new BorderPane(); /* layout -> center */ VBox tableViewsContainer = new VBox(5); /* layout -> center -> top */ String[] patientColumnNames = new String[] {"Patient ID", "First Name", "Last Name", "Gender", "Date Of Birth", "Age", "Email", "Phone Number", "City"}; String[] patientVariablesNames = Patient.getVariablesNames(); ObservableList patientData = FXCollections.observableArrayList(new Patient("Patient ID", "First Name", "Last Name", "Gender", "Date Of Birth", "Age", "Email", "Phone Number", "City")); TableViewCustom patientTableView = new TableViewCustom(patientColumnNames, patientVariablesNames, patientData); /* layout -> center -> bottom */ String[] traceColumnNames = new String[] {"Action", "Status", "Message", "Time"}; String[] traceVariablesNames = Trace.getVariablesNames(); ObservableList traceData = FXCollections.observableArrayList(new Trace("Action", "Status", "Message", "Time")); TableViewCustom traceTableView = new TableViewCustom(traceColumnNames, traceVariablesNames, traceData); /* add items to the layout */ tableViewsContainer.getChildren().addAll(patientTableView, traceTableView); layout.setCenter(tableViewsContainer); return layout; } @Override public void start(Stage stage) throws Exception { stage.setScene(new Scene(createContent())); stage.setWidth(700); stage.setHeight(400); stage.show(); } public static void main(String args[]) { launch(args); } }
Demo.java应用程序的结果如下所示:
PS我没有收到任何错误。
问题是传递给PropertyValueFactory
的值与PropertyValueFactory
的名称不匹配,属性的名称由get...()
和set...(...)
方法定义。
由于您使用reflection来查找已定义的字段 (而不是属性)的名称,因此对于Trace
类,传递给PropertyValueFactory
的值是“action”,“status”,“message”和“time”。 因此,表视图将尝试通过在每行的Trace
对象上调用getAction()
, getStatus()
, getMessage()
和getTime()
来填充列的值。 由于没有这样的方法,您不会显示任何值。
要解决此问题,您可以执行以下操作之一:
- 硬编码
getVariablesNames()
方法中定义的值以返回属性的名称(即return new String[] {"actionText", "statusText", "messageText", "timeText"};
)。 由于您在每个类中重复该方法而不是重复使用它,因此您不会使事情变得更加冗长,并且这可能会更好地执行(尽管您不太可能在实践中观察到任何差异)。 - 使用reflection,但查找声明的方法的名称,找到所有以“get”或“is”开头的内容,剥去该前缀,并小写剩下的第一个字符。
- 使字段名称与属性名称匹配(
actionText
字段声明为actionText
等)。 这当然会对您的类定义强加约定要求。