我刚刚开始使用Hibernate和JavaFX。在我的测试应用程序中,用户可以输入Person
的联系方式(姓名,地址,街道,邮政编码,城市)并将其保存到数据库中。 TextFields下面的TableView应该显示现有数据:
Screenshot of the test program
目前,我一直坚持将输入文本字段连接到模型类。使用JavaFX的StringProperty
和IntegerProperty
对象进行映射本身是可行的,但是我认为我做错了方法。
将Person
对象保存到数据库后,我想清除输入字段,以便用户可以创建新的Person
。为此,我必须删除所有Model-GUI映射,创建一个新对象,然后重新映射所有内容。另外,如果用户选择tableView中的现有条目之一,那么我想用所选对象填充输入字段,以便用户可以更新条目。这也将需要重新进行所有属性映射。这听起来是错误的,所以我认为必须有一个更好的解决方案。
我考虑过仅在用户单击保存按钮然后执行所有StringProperty映射时创建一个Person
对象,但这也是很多开销。我也可以使用普通的字符串,然后省略Property-class。
您对我有什么建议或资源吗?
这是控制器类:
package test.gui;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.util.converter.NumberStringConverter;
import org.hibernate.Session;
import test.models.Person;
import javax.persistence.TypedQuery;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import static test.Database.getFactory;
public class MainWindowController implements Initializable {
@FXML
private TextField firstName;
@FXML
private TextField lastName;
@FXML
private TextField street;
@FXML
private TextField zip;
@FXML
private TextField city;
@FXML
private TableView<Person> tableView;
@FXML
private TableColumn<Person, String> tblFirstName;
@FXML
private TableColumn<Person, String> tblLastName;
@FXML
private TableColumn<Person, String> tblStreet;
@FXML
private TableColumn<Person, Integer> tblZip;
@FXML
private TableColumn<Person, String> tblCity;
private Person currentPerson = null;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// Map table columns to Person model
tblFirstName.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
tblLastName.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
tblStreet.setCellValueFactory(cellData -> cellData.getValue().streetProperty());
tblZip.setCellValueFactory(cellData -> cellData.getValue().zipProperty().asObject());
tblCity.setCellValueFactory(cellData -> cellData.getValue().cityProperty());
// Read values from database to TableView
Session s = getFactory().openSession();
TypedQuery<Person> query = s.createQuery("from Person", Person.class);
List<Person> persons = query.getResultList();
s.close();
tableView.getItems().addAll(persons);
// Bind TextFields to Model
currentPerson = new Person();
firstName.textProperty().bindBidirectional(currentPerson.firstNameProperty());
lastName.textProperty().bindBidirectional(currentPerson.lastNameProperty());
street.textProperty().bindBidirectional(currentPerson.streetProperty());
zip.textProperty().bindBidirectional(currentPerson.zipProperty(), new NumberStringConverter());
city.textProperty().bindBidirectional(currentPerson.cityProperty());
// This does not work because apparently, newValue is read-only
tableView.getSelectionModel().selectedItemProperty().addListener((v, oldValue, newValue) -> {
currentPerson = newValue;
});
}
public void savePerson() {
Session s = getFactory().openSession();
s.getTransaction().begin();
s.persist(currentPerson);
s.getTransaction().commit();
s.close();
tableView.getItems().add(currentPerson);
// Todo: Create new, empty Person object and map it to TextFields
// Better solution?
}
}
这是FXML文件:
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="5.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.gui.MainWindowController">
<children>
<GridPane hgap="5.0" vgap="5.0">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="NEVER" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="First Name" />
<Label text="Last Name" GridPane.rowIndex="1" />
<Label text="Street" GridPane.rowIndex="2" />
<Label text="ZIP" GridPane.columnIndex="2" />
<Label text="City" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<TextField fx:id="firstName" GridPane.columnIndex="1" />
<TextField fx:id="lastName" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<TextField fx:id="street" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextField fx:id="zip" GridPane.columnIndex="3" />
<TextField fx:id="city" GridPane.columnIndex="3" GridPane.rowIndex="1" />
<Button fx:id="saveButton" mnemonicParsing="false" onAction="#savePerson" text="Save" GridPane.columnIndex="3" GridPane.rowIndex="2" />
</children>
</GridPane>
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn fx:id="tblFirstName" prefWidth="75.0" text="First Name" />
<TableColumn fx:id="tblLastName" prefWidth="75.0" text="Last Name" />
<TableColumn fx:id="tblStreet" prefWidth="75.0" text="Street" />
<TableColumn fx:id="tblZip" prefWidth="75.0" text="Zip" />
<TableColumn fx:id="tblCity" prefWidth="75.0" text="City" />
</columns>
</TableView>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</VBox>
非常感谢您。