问题概述:
我有两个模型OrderModel
和OrderStatusModel
。 OrderStatusModel
项放入组合框中,组合框包含用户更新Order
表中名为orderStatusId
的外键字段的选项。初始化数据时,我希望能够从OrderModel
拉出并检索当前orderStatusId
,然后设置组合框(包含所有用户选择)以匹配位于orderStatusId
的{{1}}在OrderModel
(其中包含位于Order
表中的FK)。组合框需要能够在进行新选择时更新OrderModel
。在从数据库中获取数据以填充OrderModel
时,我会提取我的FK orderStatusId
。从这一点开始,我使用case语句在OrderStatusModel
中选择适当的项,并在初始化时选择选项。我知道这不是最好的方法,因为如果我要在后端数据库中为新类型的状态添加一个新行(例如:取消订单),那么我需要将所有的switch语句更新为允许这种变化。
示例代码
Controller
package test.pkg2;
import java.awt.Label;
import java.beans.Statement;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
public class Test2Controller implements Initializable{
@FXML
private Label customerName;
@FXML
private Label orderNumber;
@FXML
private Label orderStatusId;
@FXML
private ComboBox<OrderStatusModel> orderStatusCmb;
private ObservableList<OrderStatusModel> orderStatusModel;
private ObservableList<OrderModel> orderModel;
int statusId;
@Override
public void initialize(URL location, ResourceBundle resources) {
this.orderStatusCmb.getSelectionModel().selectedItemProperty().addListener((obs, newValue, oldValue) ->{
if(newValue != null && newValue != oldValue){
this.orderStatusCmb.getSelectionModel().getSelectedItem().getOrderStatusId();
//TODO UPDATE Order table with new orderStatusId from above code ^^^^^^
}
});
populateOrderStatusCombobox();
getCurrentOrder();
}
private void populateOrderStatusCombobox(){
String SQL = "SELECT Status.statusId, Status.statusName \n"
+"FROM Status;";
orderStatusModel = FXCollections.observableArrayList();
//Status table:
// +-----------+-------------+------+-----+---------+
// | Field | Type | Null | Key | Default |
// +-----------+-------------+------+-----+---------+
// | statusId | int | YES | PK | NULL |
// | statusName| varchar(20) | YES | | NULL |
// +-----------+-------------+------+-----+---------+
//example data: statusId = 1 statusName = Order Taken
//example data: statusId = 2 statusName = Order Processing
//example data: statusId = 3 statusName = Shipped
//Above items are populated into the combobox for selection
try(Connection connection = DBConnection.getConnection()){
PreparedStatement statement = connection.prepareStatement(SQL);
ResultSet resultSet = statement.executeQuery();
while(resultSet.next()){
this.orderStatusModel.add(new OrderStatusModel(resultSet.getInt("statusId"),
resultSet.getString("statusName")));
}
} catch(SQLException e){
}
this.orderStatusCmb.setItems(orderStatusModel);
}
private void getCurrentOrder(){
String SQL = "SELECT Order.orderNumber, Order.customerName, Order.orderStatusId \n"
+"FROM Order"
+"WHERE orderNumber = 123;";
orderModel = FXCollections.observableArrayList();
//Order table:
// +--------------+-------------+------+-----+---------+
// | Field | Type | Null | Key | Default |
// +--------------+-------------+------+-----+---------+
// | orderNumber | int | YES | PK | NULL |
// | customerName | varchar(20) | YES | | NULL |
// | orderStatusId| int | YES | FK | NULL |
// +--------------+-------------+------+-----+---------+
//example data: orderNumber = 123
// customerName = SomeCompany
// orderStatusId = 1
//I usually set the combobox here using the below method:
try(Connection connection = DBConnection.getConnection()){
PreparedStatement statement = connection.prepareStatement(SQL);
ResultSet resultSet = statement.executeQuery();
while(resultSet.next()){
this.orderModel.add(new OrderModel(resultSet.getInt("orderNumber"),
resultSet.getString("customerName"),
resultSet.getInt("orderStatusId")));
statusId = resultSet.getInt("orderStatusId");
}
//HERE is where I initially set the orderStatus to match the orderModel
//I am guessing I need some kind of binding here?
switch(statusId){
case 1: this.orderStatusCmb.getSelectionModel().select(0);
break;
case 2: this.orderStatusCmb.getSelectionModel().select(1);
break;
case 3: this.orderStatusCmb.getSelectionModel().select(3);
break;
}
} catch(SQLException e){
}
}
}
OrderStatusModel
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class OrderStatusModel {
private final IntegerProperty orderStatusId;
private final StringProperty orderStatusName;
public OrderStatusModel(int orderStatusId, String orderStatusName){
this.orderStatusId = new SimpleIntegerProperty(orderStatusId);
this.orderStatusName = new SimpleStringProperty(orderStatusName);
}
public IntegerProperty getOrderStatusId() {
return orderStatusId;
}
public StringProperty getOrderStatusName() {
return orderStatusName;
}
}
OrderModel
package test.pkg2;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class OrderModel {
private final IntegerProperty orderNumber;
private final StringProperty customerName;
private final IntegerProperty orderStatusId;
public OrderModel(int orderNumber, String customerName, int orderStatusId){
this.orderNumber = new SimpleIntegerProperty(orderNumber);
this.customerName = new SimpleStringProperty(customerName);
this.orderStatusId = new SimpleIntegerProperty(orderStatusId);
}
public IntegerProperty getOrderNumber() {
return orderNumber;
}
public StringProperty getCustomerName() {
return customerName;
}
public IntegerProperty getOrderStatusId() {
return orderStatusId;
}
}
答案 0 :(得分:0)
您不需要使用任何显式绑定来实现选项和ID之间的链接。相反,通过OrderStatusModel对象支持组合框,该对象已包含ID和友好字符串名称,然后将适当的StringConverter应用于组合框将实现组合框的良好显示。 id - &gt;友好名称链接仍保留在模型类中,可根据需要在后续数据库更新中反向使用。
<强>示例强>
这个样本的作用是:
示例输出
ComboApp.java
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import java.util.Optional;
public class ComboApp extends Application {
private Label orderNumber = new Label();
private Label customerName = new Label();
private ComboBox<OrderStatusModel> orderStatus = new ComboBox<>();
private Database database = new InMemoryTestDatabase();
@Override
public void start(Stage stage) throws Exception {
HBox layout = new HBox(
10,
orderNumber,
customerName,
orderStatus
);
layout.setPadding(new Insets(10));
layout.setAlignment(Pos.BASELINE_LEFT);
populateOrderStatusCombobox();
showOrder(123);
updateOrderWhenStatusChanged();
stage.setScene(new Scene(layout));
stage.show();
}
private void updateOrderWhenStatusChanged() {
orderStatus.valueProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null && !newValue.equals(oldValue)) {
database.updateOrder(
new OrderModel(
Integer.parseInt(orderNumber.getText()),
customerName.getText(),
orderStatus.getValue()
)
);
System.out.println(
"Updated order status of order "
+ orderNumber.getText()
+ " to "
+ orderStatus.getValue()
.orderStatusNameProperty()
.getValue()
);
}
});
}
private void populateOrderStatusCombobox(){
orderStatus.setPlaceholder(new Label("None Selected"));
orderStatus.getItems().setAll(database.listAllOrderStatuses());
orderStatus.setConverter(new StringConverter<OrderStatusModel>() {
@Override
public String toString(OrderStatusModel orderStatusModel) {
return orderStatusModel.orderStatusNameProperty().get();
}
@Override
public OrderStatusModel fromString(String orderStatusName) {
Optional<OrderStatusModel> result = database.findOrderStatusWithName(
orderStatusName
);
return result.orElse(null);
}
});
}
private void showOrder(int orderId){
Optional<OrderModel> result = database.findOrderById(orderId);
if (!result.isPresent()) {
orderNumber.setText("");
customerName.setText("");
orderStatus.setValue(null);
return;
}
OrderModel order = result.get();
orderNumber.setText("" + order.orderNumberProperty().get());
customerName.setText(order.customerNameProperty().get());
orderStatus.setValue(order.orderStatusProperty().get());
}
public static void main(String[] args) {
launch(args);
}
}
Database.java
import java.util.List;
import java.util.Optional;
public interface Database {
List<OrderStatusModel> listAllOrderStatuses();
Optional<OrderStatusModel> findOrderStatusWithName(String orderStatusName);
Optional<OrderStatusModel> findOrderStatusById(int orderStatusId);
Optional<OrderModel> findOrderById(int orderId);
void updateOrder(OrderModel order);
}
InMemoryTestDatabase.java
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class InMemoryTestDatabase implements Database {
List<OrderStatusModel> orderStatuses = new ArrayList<>();
List<OrderModel> orders = new ArrayList<>();
public InMemoryTestDatabase() {
// populate with dummy sample data.
orderStatuses.add(new OrderStatusModel(1, "Order Taken"));
orderStatuses.add(new OrderStatusModel(2, "Order Processing"));
orderStatuses.add(new OrderStatusModel(3, "Shipped"));
orders.add(
new OrderModel(
123,
"XYZZY",
findOrderStatusById(1)
.orElse(null)
)
);
}
public List<OrderStatusModel> listAllOrderStatuses() {
return orderStatuses;
}
@Override
public Optional<OrderStatusModel> findOrderStatusWithName(String orderStatusName) {
return orderStatuses.stream()
.filter(orderStatus -> orderStatusName.equals(orderStatus.orderStatusNameProperty().get()))
.findFirst();
}
@Override
public Optional<OrderStatusModel> findOrderStatusById(int orderStatusId) {
return orderStatuses.stream()
.filter(orderStatus -> orderStatusId == orderStatus.orderStatusIdProperty().get())
.findFirst();
}
public Optional<OrderModel> findOrderById(int orderId) {
return orders.stream()
.filter(order -> orderId == order.orderNumberProperty().get())
.findFirst();
}
public void updateOrder(OrderModel order) {
for (int i = 0; i < orders.size(); i++) {
if (orders.get(i).orderNumberProperty().get() == order.orderNumberProperty().get()) {
orders.set(i, order);
break;
}
}
}
}
OrderModel.java
import javafx.beans.property.*;
public class OrderModel {
private final IntegerProperty orderNumber;
private final StringProperty customerName;
private final ObjectProperty<OrderStatusModel> orderStatus;
public OrderModel(int orderNumber, String customerName, OrderStatusModel orderStatus){
this.orderNumber = new SimpleIntegerProperty(orderNumber);
this.customerName = new SimpleStringProperty(customerName);
this.orderStatus = new SimpleObjectProperty<>(orderStatus);
}
public IntegerProperty orderNumberProperty() {
return orderNumber;
}
public StringProperty customerNameProperty() {
return customerName;
}
public ObjectProperty<OrderStatusModel> orderStatusProperty() {
return orderStatus;
}
}
OrderStatusModel.java
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import java.util.Objects;
public class OrderStatusModel {
private final IntegerProperty orderStatusId;
private final StringProperty orderStatusName;
public OrderStatusModel(int orderStatusId, String orderStatusName){
this.orderStatusId = new SimpleIntegerProperty(orderStatusId);
this.orderStatusName = new SimpleStringProperty(orderStatusName);
}
public IntegerProperty orderStatusIdProperty() {
return orderStatusId;
}
public StringProperty orderStatusNameProperty() {
return orderStatusName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrderStatusModel that = (OrderStatusModel) o;
return Objects.equals(orderStatusId.get(), that.orderStatusId.get()) &&
Objects.equals(orderStatusName.get(), that.orderStatusName.get());
}
@Override
public int hashCode() {
return Objects.hash(orderStatusId.get(), orderStatusName.get());
}
}
<强>背景强>
这个答案基于JavaFX论坛帖子中的类似问题和答案,该帖子与ChoiceBoxes而不是ComboBoxes相关:
但是,此答案已更新为直接使用ComboBox而不是ChoiceBox。
无关建议
关于您发布的代码的一些不相关的建议:
java.awt.Label
然后尝试使用FXML进行注入:这不对,您应该使用javafx.scene.control.Label
。不要混合使用awt代码和JavaFX代码。