使用 FXML 初始化带有 fx:root 内列的 TableView
Initializing TableView with columns inside fx:root using FXML
我在名为 TablePatientView
的 fxml 文件中有一个自定义 class。我像 <TablePatientView fx:id="tablePatientView" layoutX="20.0" layoutY="45.0" prefHeight="409.0" prefWidth="363.0" />
一样使用它,它几乎可以正常工作。 fx:root
如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<fx:root type="javafx.scene.control.TableView" xmlns:fx="http://javafx.com/fxml">
<TableView>
<columns>
<TableColumn fx:id="patId" prefWidth="101.0" text="Patient-ID" />
<TableColumn fx:id="patVorname" prefWidth="69.0" text="Vorname" />
<TableColumn fx:id="patNachname" prefWidth="98.0" text="Nachname" />
<TableColumn fx:id="patGebdat" prefWidth="96.0" text="Geburtsdatum" />
</columns>
</TableView>
</fx:root>
与以下 class
public class TablePatientView extends TableView<TablePatient> {
private Parent root;
@FXML
private TableColumn<TablePatient,String> patId;
@FXML
private TableColumn<TablePatient,String> patVorname;
@FXML
private TableColumn<TablePatient,String> patNachname;
@FXML
private TableColumn<TablePatient, LocalDate> patGebdat;
public TablePatientView() {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/fxml/TablePatientView.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
root = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
setCellValueFactories();
// getColumns().addAll(patId, patVorname, patNachname, patGebdat); works, but not with plain fxml
}
private void setCellValueFactories() {
patId.setCellValueFactory(param -> param.getValue().idProperty().asString());
patVorname.setCellValueFactory(param -> param.getValue().vornameProperty());
patNachname.setCellValueFactory(param -> param.getValue().nachnameProperty());
patGebdat.setCellValueFactory(param -> param.getValue().gebDatProperty());
}
}
列已正确初始化,但由于某种原因未作为列添加到 TableView。
我知道我可以通过 java 代码来做到这一点(请参阅上面代码中的注释行)但我想知道为什么这不适用于 fxml。在没有自定义 class 和 root 的情况下直接在 fxml 中使用 就可以了。
<fx:root type="TableView">
引用 TableView
,它是通过调用 loader.setRoot(this)
.
提供的
您在 TableView
1 中定义了另一个 TableView
。这些列被添加到 TableView
,而不是 <fx:root>
.
引用的列
正确的 FXML 是
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<fx:root type="javafx.scene.control.TableView" xmlns:fx="http://javafx.com/fxml">
<columns>
<TableColumn fx:id="patId" prefWidth="101.0" text="Patient-ID" />
<TableColumn fx:id="patVorname" prefWidth="69.0" text="Vorname" />
<TableColumn fx:id="patNachname" prefWidth="98.0" text="Nachname" />
<TableColumn fx:id="patGebdat" prefWidth="96.0" text="Geburtsdatum" />
</columns>
</fx:root>
替代方法
我不太喜欢子类化控件 类,例如 TableView
。原因是您并没有真正向 TableView
添加功能,您实际上只是在其上设置属性,这不是对继承的良好使用。
考虑使用创建模式。一个简单的静态工厂方法运行良好,并通过 fx:factory
属性与 FXML 很好地配合使用。
TablePatientView.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<TableView xmlns:fx="http://javafx.com/fxml" fx:controller="com.jamesd.examples.TablePatientController">
<columns>
<TableColumn fx:id="patId" prefWidth="101.0" text="Patient-ID" />
<TableColumn fx:id="patVorname" prefWidth="69.0" text="Vorname" />
<TableColumn fx:id="patNachname" prefWidth="98.0" text="Nachname" />
<TableColumn fx:id="patGebdat" prefWidth="96.0" text="Geburtsdatum" />
</columns>
</TableView>
TablePatientController.java:
public class TablePatientController {
@FXML
private TableColumn<TablePatient,String> patId;
@FXML
private TableColumn<TablePatient,String> patVorname;
@FXML
private TableColumn<TablePatient,String> patNachname;
@FXML
private TableColumn<TablePatient, LocalDate> patGebdat;
@FXML
private void initialize() {
setCellValueFactories();
}
private void setCellValueFactories() {
patId.setCellValueFactory(param -> param.getValue().idProperty().asString());
patVorname.setCellValueFactory(param -> param.getValue().vornameProperty());
patNachname.setCellValueFactory(param -> param.getValue().nachnameProperty());
patGebdat.setCellValueFactory(param -> param.getValue().gebDatProperty());
}
}
Tables.java:
public class Tables {
public static TableView<TablePatient> tablePatientView() throws Exception {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/fxml/TablePatientView.fxml"));
return loader.load();
}
}
然后您可以在 FXML 中使用它
<Tables fx:factory="tablePatientView" />
脚注
- 这里发生的是第二个
TableView
被添加到原始 TableView
的 items
列表中,因为 TableView
的 @DefaultProperty
是那个清单。所以最终 table 视图会尝试将其显示为 table 中的一行。似乎在某个时候应该有一个 ClassCastException
,但它可能会被静静地压扁,因为 FXML 无法指定泛型类型。
我在名为 TablePatientView
的 fxml 文件中有一个自定义 class。我像 <TablePatientView fx:id="tablePatientView" layoutX="20.0" layoutY="45.0" prefHeight="409.0" prefWidth="363.0" />
一样使用它,它几乎可以正常工作。 fx:root
如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<fx:root type="javafx.scene.control.TableView" xmlns:fx="http://javafx.com/fxml">
<TableView>
<columns>
<TableColumn fx:id="patId" prefWidth="101.0" text="Patient-ID" />
<TableColumn fx:id="patVorname" prefWidth="69.0" text="Vorname" />
<TableColumn fx:id="patNachname" prefWidth="98.0" text="Nachname" />
<TableColumn fx:id="patGebdat" prefWidth="96.0" text="Geburtsdatum" />
</columns>
</TableView>
</fx:root>
与以下 class
public class TablePatientView extends TableView<TablePatient> {
private Parent root;
@FXML
private TableColumn<TablePatient,String> patId;
@FXML
private TableColumn<TablePatient,String> patVorname;
@FXML
private TableColumn<TablePatient,String> patNachname;
@FXML
private TableColumn<TablePatient, LocalDate> patGebdat;
public TablePatientView() {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/fxml/TablePatientView.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
root = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
setCellValueFactories();
// getColumns().addAll(patId, patVorname, patNachname, patGebdat); works, but not with plain fxml
}
private void setCellValueFactories() {
patId.setCellValueFactory(param -> param.getValue().idProperty().asString());
patVorname.setCellValueFactory(param -> param.getValue().vornameProperty());
patNachname.setCellValueFactory(param -> param.getValue().nachnameProperty());
patGebdat.setCellValueFactory(param -> param.getValue().gebDatProperty());
}
}
列已正确初始化,但由于某种原因未作为列添加到 TableView。
我知道我可以通过 java 代码来做到这一点(请参阅上面代码中的注释行)但我想知道为什么这不适用于 fxml。在没有自定义 class 和 root 的情况下直接在 fxml 中使用
<fx:root type="TableView">
引用 TableView
,它是通过调用 loader.setRoot(this)
.
您在 TableView
1 中定义了另一个 TableView
。这些列被添加到 TableView
,而不是 <fx:root>
.
正确的 FXML 是
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<fx:root type="javafx.scene.control.TableView" xmlns:fx="http://javafx.com/fxml">
<columns>
<TableColumn fx:id="patId" prefWidth="101.0" text="Patient-ID" />
<TableColumn fx:id="patVorname" prefWidth="69.0" text="Vorname" />
<TableColumn fx:id="patNachname" prefWidth="98.0" text="Nachname" />
<TableColumn fx:id="patGebdat" prefWidth="96.0" text="Geburtsdatum" />
</columns>
</fx:root>
替代方法
我不太喜欢子类化控件 类,例如 TableView
。原因是您并没有真正向 TableView
添加功能,您实际上只是在其上设置属性,这不是对继承的良好使用。
考虑使用创建模式。一个简单的静态工厂方法运行良好,并通过 fx:factory
属性与 FXML 很好地配合使用。
TablePatientView.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<TableView xmlns:fx="http://javafx.com/fxml" fx:controller="com.jamesd.examples.TablePatientController">
<columns>
<TableColumn fx:id="patId" prefWidth="101.0" text="Patient-ID" />
<TableColumn fx:id="patVorname" prefWidth="69.0" text="Vorname" />
<TableColumn fx:id="patNachname" prefWidth="98.0" text="Nachname" />
<TableColumn fx:id="patGebdat" prefWidth="96.0" text="Geburtsdatum" />
</columns>
</TableView>
TablePatientController.java:
public class TablePatientController {
@FXML
private TableColumn<TablePatient,String> patId;
@FXML
private TableColumn<TablePatient,String> patVorname;
@FXML
private TableColumn<TablePatient,String> patNachname;
@FXML
private TableColumn<TablePatient, LocalDate> patGebdat;
@FXML
private void initialize() {
setCellValueFactories();
}
private void setCellValueFactories() {
patId.setCellValueFactory(param -> param.getValue().idProperty().asString());
patVorname.setCellValueFactory(param -> param.getValue().vornameProperty());
patNachname.setCellValueFactory(param -> param.getValue().nachnameProperty());
patGebdat.setCellValueFactory(param -> param.getValue().gebDatProperty());
}
}
Tables.java:
public class Tables {
public static TableView<TablePatient> tablePatientView() throws Exception {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/fxml/TablePatientView.fxml"));
return loader.load();
}
}
然后您可以在 FXML 中使用它
<Tables fx:factory="tablePatientView" />
脚注
- 这里发生的是第二个
TableView
被添加到原始TableView
的items
列表中,因为TableView
的@DefaultProperty
是那个清单。所以最终 table 视图会尝试将其显示为 table 中的一行。似乎在某个时候应该有一个ClassCastException
,但它可能会被静静地压扁,因为 FXML 无法指定泛型类型。