如何在JavaFx中创建通用TableView?

我正在为我的项目构建一个GUI,我需要显示来自各种类型的数据结构的信息:表中的ArrayList,HashMap,TreeSet。

基本上我需要显示我在视图包中的模型包中获得的查询方法的信息。

我的实现现在包括一个控制器,用于我每次声明TableView时使用指定的对象类型构建的每个表。

我想知道是否有一种方法来创建一个类,它的构造函数将构建我需要的表(具有此对象所需的列数)。 某种通用表构建器,可以读取对象并找出需要表示的列数。 例如:提供具有4个字段/列的Reservation对象与具有6个字段/列的Member对象进行比较。 根据它将得到的数据结构。 因此,我将能够创建此类的实例并实例化我需要的表并在屏幕上显示它。

我还需要一种能够从场景构建器控制它的方法,因为这是我用于以图形方式构建GUI的主要工具。

我在这里添加了一个表格代码,希望有人可以帮我完成这个繁琐的任务:)

package view; import java.util.ArrayList; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.stage.Stage; import model.Reservation; public class QRYClientReservationsTableController { private ObservableList ReservationsData = FXCollections.observableArrayList(); @FXML private TableView ReservationforClient; @FXML private TableColumn ReservationIdColumn; @FXML private TableColumn LocationIdColumn; @FXML private TableColumn AddressColumn; @FXML private TableColumn DescriptionColumn; @FXML private TableColumn StartTimeAndDateColumn; @FXML private TableColumn EndTimeAndDateColumn; @FXML private TextField memId; /** * The constructor. * The constructor is called before the initialize() method. */ public QRYClientReservationsTableController() { } /** * Initializes the controller class. This method is automatically called * after the fxml file has been loaded. */ @FXML private void initialize() { // Initialize the Location table with the tree columns. ReservationIdColumn.setCellValueFactory(cellData -> cellData.getValue().ReservationIdProperty()); LocationIdColumn.setCellValueFactory(cellData -> cellData.getValue().LocationIdProperty()); AddressColumn.setCellValueFactory(cellData -> cellData.getValue().LocationAddressProperty()); DescriptionColumn.setCellValueFactory(cellData -> cellData.getValue().LocationDescriptionProperty()); StartTimeAndDateColumn.setCellValueFactory(cellData -> cellData.getValue().StartDateProperty()); EndTimeAndDateColumn.setCellValueFactory(cellData -> cellData.getValue().EndDateProperty()); } @FXML Button CloseBtn = new Button();//close button inside AddLocation window @FXML public void handleCloseButtonAction(ActionEvent event) {//for all close Button's this method is called Stage stage = (Stage) CloseBtn.getScene().getWindow(); stage.close(); } /** * Is called by the main application to give a reference back to itself. * * @param Locaion */ public void setQRYClientReservationsTableController(String memId) { this.memId.setEditable(true); this.memId.setText(memId); this.memId.setEditable(false); ArrayList reservationsAdd = new ArrayList(); reservationsAdd.addAll(ViewLogic.controlLogic.Q_getAllReservationsForMember(memId)); ReservationsData.addAll(reservationsAdd); // Add observable list data to the table ReservationforClient.setItems(ReservationsData); ReservationIdColumn.sortableProperty().setValue(false); LocationIdColumn.sortableProperty().setValue(false); AddressColumn.sortableProperty().setValue(false); DescriptionColumn.sortableProperty().setValue(false); StartTimeAndDateColumn.sortableProperty().setValue(false); EndTimeAndDateColumn.sortableProperty().setValue(false); } } 

下一个代码在我的View包中的ViewLogic类中,这个代码召唤FXML文件加载一个小窗口来选择一个成员Id,通过这个Id我得到的信息是在上面的代码上构建表。 ViewLogic中此方法的代码如下:

 @FXML Button ShowReservationsForClientBtn= new Button();/*Code for pressing the get reservations for client button to open window after pressing the button in Queries*/ @FXML public void pressShowReservationsForClientBtn(ActionEvent event) throws Exception { try { FXMLLoader fxmlLoader = new FXMLLoader(ChooseAClientForReservationsQueryWindowController.class.getResource("/view/ChooseAClientForReservationsQueryWindow.fxml")); AnchorPane chooseMemberIdForQuery = (AnchorPane) fxmlLoader.load(); ChooseAClientForReservationsQueryWindowController controller = fxmlLoader.getController(); controller.setAddTripToReservationClass(); Stage stage = new Stage(); stage.setTitle("Please Choose a Member Id"); stage.setScene(new Scene(chooseMemberIdForQuery)); stage.show(); } catch(Exception e) { e.printStackTrace(); } } 

然后它会在您选择成员的位置调用此类,然后启动上面的表代码,迷你窗口代码为:

 package view; import java.util.ArrayList; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; import javafx.scene.control.Alert.AlertType; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; public class ChooseAClientForReservationsQueryWindowController { private String memIdChosen; @FXML private ComboBox MemberIds; public void initialize() { } @FXML Button CloseBtn = new Button();//close button inside AddLocation window @FXML public void handleCloseButtonAction(ActionEvent event) {//for all close Button's this method is called Stage stage = (Stage) CloseBtn.getScene().getWindow(); stage.close(); } @FXML Button EraseBtn = new Button();//erase Button @FXML public void handleEraseButtonAction(ActionEvent event) {//erase Button code MemberIds.setValue(null); } @FXML Button GoBtn = new Button();//Go button @FXML public void handleGoBtn(ActionEvent event) throws Exception {//for all close Button's this method is called try{ if(MemberIds.getValue()==null) throw new Exception(); FXMLLoader fxmlLoader = new FXMLLoader(QRYClientReservationsTableController.class.getResource("/view/QRYClientReservationsTableController.fxml")); AnchorPane qryShowAllReservationsForMember = (AnchorPane) fxmlLoader.load(); QRYClientReservationsTableController controller = fxmlLoader.getController(); controller.setQRYClientReservationsTableController(memIdChosen); Stage stage = new Stage(); stage.setTitle("Query - Show all reservations for member Id: "+memIdChosen+"."); stage.setScene(new Scene(qryShowAllReservationsForMember)); stage.show(); handleCloseButtonAction(event); } catch (Exception e){ Alert alert = new Alert(AlertType.WARNING,"One of the fields is empty", ButtonType.OK); alert.setTitle("One of the fields is empty"); alert.setHeaderText("One of the fields is empty"); alert.setContentText("Please fill the empty fields"); alert.showAndWait(); } } /** * The constructor. * The constructor is called before the initialize() method. */ public ChooseAClientForReservationsQueryWindowController() { } public void setAddTripToReservationClass(){ ArrayList memIds = new ArrayList(); memIds.addAll(ViewLogic.controlLogic.getMembers().keySet()); MemberIds.getItems().setAll(memIds); MemberIds.valueProperty().addListener(new ChangeListener(){ @Override public void changed(ObservableValue arg0, String arg1, String arg2) { memIdChosen=arg2; } }); } } 

如果它有帮助,那就是上面表格代码的相关FXML文件:

           

谢谢

汤姆

我偶然发现了类似的问题并创建了一个解决它的简单库。

它使用您的模型类来构建表示给定类的字段的TableView。

我已经在GitHub上发布了一个示例和说明。

如果您有任何建议,我想听听您的意见。

你可以通过反思来做到这一点。 这将为每个SimpleStringProperty字段创建一个可编辑的String列。 这样做意味着您无法在FXML中添加它们。

  for (Field f : TableInfo.class.getDeclaredFields()) { if (f.getType().equals(SimpleStringProperty.class)){ TableColumn tc = new TableColumn<>(f.getName()); tv.getColumns().add(tc); tc.setCellValueFactory(new PropertyValueFactory<>(f.getName())); tc.setCellFactory(TextFieldTableCell.forTableColumn()); }//else if more field types... }