我有一张表格,显示有关多次旅行的信息。其中一列是驱动程序,它告诉谁被指定为某次旅行的驾驶员。我想要实现的是,如果没有分配驱动程序(数据库中为null),您应该能够单击该特定单元格中的按钮并选择驱动程序。
我在下面找到了问题,但我不确定如何在我的系统中实现该解决方案。 JavaFX 2 TableView : different cell factory depending on the data inside the cell
我应该研究什么?是否有记录的方法来实现这一目标?
以下是代码:
public class BookViewController {
private String dbUrl = "jdbc:postgresql://localhost:5432/BookingApp";
private String dbUsername = "postgres";
private String dbPassword = "secret";
@FXML
private TextField personnr;
@FXML
private TextField name;
@FXML
private TextField email;
@FXML
private TextField telnr;
@FXML
private Button addTraveler;
@FXML
private Button removeTraveler;
@FXML
private TableView<Traveler> travelers;
@FXML
private TableColumn<?, ?> personnrColumn;
@FXML
private TableColumn<?, ?> nameColumn;
@FXML
private TableColumn<?, ?> emailColumn;
@FXML
private TableColumn<?, ?> telnrColumn;
@FXML
private TableView<Trip> trips;
@FXML
private TableColumn<?, ?> originColumn;
@FXML
private TableColumn<?, ?> destinationColumn;
@FXML
private TableColumn<?, ?> departureColumn;
@FXML
private TableColumn<?, ?> arrivalColumn;
@FXML
private TableColumn<?, ?> driverColumn;
@FXML
private TableColumn<?, ?> priceAmountColumn;
@FXML
private TableColumn<?, ?> seatsColumn;
@FXML
private Button bookTrip;
private Trip rowData;
private ObservableList<Trip> tripData;
protected void initialize(Trip rowData) {
this.rowData = rowData;
addTraveler.setDisable(true);
removeTraveler.setDisable(true);
populateTravelPlan();
}
@FXML
private void populateTravelPlan() {
originColumn.setCellValueFactory(new PropertyValueFactory<>("origin"));
destinationColumn.setCellValueFactory(new PropertyValueFactory<>("destination"));
departureColumn.setCellValueFactory(new PropertyValueFactory<>("departure"));
arrivalColumn.setCellValueFactory(new PropertyValueFactory<>("arrival"));
driverColumn.setCellValueFactory(new PropertyValueFactory<>("driver"));
priceAmountColumn.setCellValueFactory(new PropertyValueFactory<>("priceAmount"));
seatsColumn.setCellValueFactory(new PropertyValueFactory<>("seats"));
try {
Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
tripData = FXCollections.observableArrayList();
ResultSet rs = null;
if(rowData.getTrip1() != 0 && rowData.getTrip2() == 0 && rowData.getTrip3() == 0) {
rs = conn.createStatement().executeQuery(
"select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" +
"from trip, connexion\r\n" +
"where trip.tripid = " + rowData.getTrip1() + "\r\n" +
"and trip.connexionid = connexion.connexionid\r\n" +
"order by departure;");
} else if(rowData.getTrip1() != 0 && rowData.getTrip2() != 0 && rowData.getTrip3() == 0) {
rs = conn.createStatement().executeQuery(
"select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" +
"from trip, connexion\r\n" +
"where trip.tripid = " + rowData.getTrip1() + "\r\n" +
"and trip.connexionid = connexion.connexionid\r\n" +
"union\r\n" +
"select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" +
"from trip, connexion\r\n" +
"where trip.tripid = " + rowData.getTrip2() + "\r\n" +
"and trip.connexionid = connexion.connexionid\r\n" +
"order by departure;");
} else if(rowData.getTrip1() != 0 && rowData.getTrip2() != 0 && rowData.getTrip3() != 0) {
rs = conn.createStatement().executeQuery(
"select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" +
"from trip, connexion\r\n" +
"where trip.tripid = " + rowData.getTrip1() + "\r\n" +
"and trip.connexionid = connexion.connexionid\r\n" +
"union\r\n" +
"select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" +
"from trip, connexion\r\n" +
"where trip.tripid = " + rowData.getTrip2() + "\r\n" +
"and trip.connexionid = connexion.connexionid\r\n" +
"union\r\n" +
"select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" +
"from trip, connexion\r\n" +
"where trip.tripid = " + rowData.getTrip3() + "\r\n" +
"and trip.connexionid = connexion.connexionid\r\n" +
"order by departure;");
}
if(rs.next()) {
tripData.add(new Trip(rs.getInt(1), rs.getString(2), rs.getString(3), ""+rs.getTimestamp(4), ""+rs.getTimestamp(5), rs.getString(6), ""+rs.getInt(7), ""+rs.getInt(8)));
while(rs.next()) {
tripData.add(new Trip(rs.getInt(1), rs.getString(2), rs.getString(3), ""+rs.getTimestamp(4), ""+rs.getTimestamp(5), rs.getString(6), ""+rs.getInt(7), ""+rs.getInt(8)));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
trips.setItems(tripData);
}
}
答案 0 :(得分:1)
根据评论编辑(感谢@fabian)。
这假设Trip
有一个方法Trip.getDriver()
,它将驱动程序作为String
返回显示。
自定义CellFactory
的{{1}}:
driverColumn
每次更新单元格时,可能还有其他选项,而不是重新创建按钮,但我希望你能得到一般的想法。
您可以使用相同的技术更改项目的显示方式(例如根据值添加样式),添加复选框等控件。
作为单独的说明,我建议您可以考虑将数据库连接代码移出Platform(JavaFX)线程,例如使用//give driverColumn proper types
TableColumn<Trip,String> driverColumn;
//...
driverColumn.setCellValueFactory(new Callback<CellDataFeatures<Trip, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<Trip, String> p) {
// p.getValue() returns the Trip instance for a particular TableView row
return new SimpleStringProperty(p.getValue().getDriver());
}
});
driverColumn.setCellFactory(param -> new TableCell<Trip,String>{
public void updateItem(String driver, boolean empty) {
super.updateItem(driver, empty);
//reset any previous values, as cells may be reused
setText(null);
setGraphic(null);
if(empty) {
//contingency if cell is empty
} else if(driver!=null) {
setText(driver);
} else {
//driver is null
Button b = new Button("Choose Driver");
//... hook up button actions, etc
setGraphic(b);
}
}
});
接口。
答案 1 :(得分:0)
为驱动程序列添加CellFactory
,并在该创建的单元格中为数据创建不同的内容:
driverColumn.setCellFactory(this::createDriverCell);
private TableCell<Trip,String> createDriverCell(TableColumn<Trip, String> table) {
return new TableCell<Trip, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
// configure empty
} else if (item == null) {
// create no driver content
} else {
// create different content
}
}
};
}
答案 2 :(得分:0)
使用cellFactory
创建显示不同内容的单元格,具体取决于单元格项目。以下代码假定您的cellValueFactory
返回ObservableValue
,它还实现了WritableValue
,并允许您以这种方式将数据存储在项目中。
为简单起见,以下示例使用StringProperty
s表(您未发布Trip
类):
@Override
public void start(Stage primaryStage) {
TableView<StringProperty> table = new TableView<>();
// fill table
for (int i = 0; i < 20; i++) {
table.getItems().add(new SimpleStringProperty());
}
TableColumn<StringProperty, String> column = new TableColumn<>();
column.setCellValueFactory(TableColumn.CellDataFeatures::getValue); // returns the row item itself
column.setCellFactory(col -> new TableCell<StringProperty, String>() {
private final Button button;
{
button = new Button("Set Value...");
button.setOnAction(evt -> {
TextInputDialog dialog = new TextInputDialog();
Optional<String> opt = dialog.showAndWait();
String result = opt.orElse(null);
if (result != null) {
ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
if (ov instanceof WritableValue) {
((WritableValue) ov).setValue(result);
}
}
});
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
// empty cell
setText("");
setGraphic(null);
} else {
if (item == null) {
// editable cell
setText("");
setGraphic(button);
} else {
// uneditable cell
setText(item);
setGraphic(null);
}
}
}
});
table.getColumns().add(column);
Scene scene = new Scene(table);
primaryStage.setScene(scene);
primaryStage.show();
}