【问题标题】:How do I create a generic TableView in JavaFx?如何在 JavaFx 中创建通用 TableView?
【发布时间】:2015-07-27 22:25:57
【问题描述】:

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

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

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

我想知道是否有一种方法可以创建一个类,它的构造函数将为我构建我需要的表(这个对象需要多少列)。某种通用的表构建器,可以读取一个对象并找出它需要表示多少列。例如:呈现具有 4 个字段/列的保留对象与具有 6 个字段/列的成员对象进行比较。根据它将获得的数据结构。因此,我将能够创建此类的一个实例并实例化我需要的表格并将其显示在屏幕上。

我还需要一种能够从场景构建器中控制它的方法,因为这是我以图形方式构建 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<Reservation> ReservationsData = FXCollections.observableArrayList();


    @FXML
    private TableView<Reservation> ReservationforClient;
    @FXML
    private TableColumn<Reservation, String> ReservationIdColumn;
    @FXML
    private TableColumn<Reservation, String> LocationIdColumn;
    @FXML
    private TableColumn<Reservation, String> AddressColumn;
    @FXML
    private TableColumn<Reservation, String> DescriptionColumn;
    @FXML
    private TableColumn<Reservation, String> StartTimeAndDateColumn;
    @FXML
    private TableColumn<Reservation, String> 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<Reservation> reservationsAdd = new ArrayList<Reservation>();
        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<String> 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<String> memIds = new ArrayList<String>();
            memIds.addAll(ViewLogic.controlLogic.getMembers().keySet());
            MemberIds.getItems().setAll(memIds);
            MemberIds.valueProperty().addListener(new ChangeListener<String>(){

                @Override
                public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2) {
                    memIdChosen=arg2;

                }
            });
        }
    }

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

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1450.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.QRYClientReservationsTableController">
   <children>
      <ButtonBar layoutX="44.0" layoutY="541.0" prefHeight="40.0" prefWidth="700.0" AnchorPane.bottomAnchor="19.0">
        <buttons>
            <Button fx:id="CloseBtn" mnemonicParsing="false" onAction="#handleCloseButtonAction" prefHeight="31.0" prefWidth="212.0" text="Close" />
        </buttons>
      </ButtonBar>
      <TableView fx:id="ReservationforClient" layoutX="5.0" layoutY="55.0" prefHeight="486.0" prefWidth="893.0" AnchorPane.bottomAnchor="59.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="2.0" AnchorPane.topAnchor="55.0">
        <columns>
          <TableColumn fx:id="ReservationIdColumn" prefWidth="121.0" text="Reservation Id" />
            <TableColumn fx:id="LocationIdColumn" prefWidth="128.0" text="Location Id" />
            <TableColumn fx:id="AddressColumn" prefWidth="276.0" text="Address" />
            <TableColumn fx:id="DescriptionColumn" prefWidth="382.0" text="Description" />
            <TableColumn fx:id="StartTimeAndDateColumn" prefWidth="282.0" text="Start Time and Date" />
            <TableColumn fx:id="EndTimeAndDateColumn" prefWidth="252.0" text="EndTime and Date" />
        </columns>
      </TableView>
      <Label layoutX="394.0" layoutY="8.0" prefHeight="40.0" prefWidth="350.0" text="Reservations for Client Id:" AnchorPane.leftAnchor="394.0" AnchorPane.rightAnchor="706.0" AnchorPane.topAnchor="8.0">
         <font>
            <Font name="System Bold" size="28.0" />
         </font>
      </Label>
      <TextField fx:id="memId" editable="false" layoutX="738.0" layoutY="10.0" prefHeight="40.0" prefWidth="191.0" />
   </children>
</AnchorPane>

谢谢

汤姆

【问题讨论】:

  • javafxdata.org 应该这样做。那里有一些教程,但我还没有尝试过。
  • 我没有看到任何教程...
  • 我只是想找到一种以通用方式创建 javafx 表的方法,就像您在扩展 AbstractTableModel 时可以在摇摆中所做的那样......在 FX 中实现它的任何帮助将不胜感激。

标签: java user-interface data-structures javafx


【解决方案1】:

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

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

我已经published it on GitHub 提供了示例和说明。

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

【讨论】:

  • 布尔值的 getterName 将是 "is"+capitalizeFirst(fieldName);
【解决方案2】:

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

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

【讨论】:

  • 是的,但我需要做到这一点,所以我将说 Reservation 的数据集合转移到一个通用类(我正在寻找构建并寻求帮助和关于如何做的想法的类)。然后它将知道为 Resevation Object 构建正确的表并将其显示在屏幕上。现在我在 Reservation 类中有返回每个 Reservation 对象的字符串属性的方法。正如您在上面看到的,我正在使用 java 8 语法来填充我的表。我的问题是它是否可以以通用方式完成。因此我不需要为每个表构建不同的类......我希望你明白我的想法。
  • 我明白了。显示您的预订课程,这就是我需要的所有代码。如果一切都是字符串,那就容易多了。如果您有 SimpStrProp reservationId = new Simpl... 之类的字段,此代码将起作用
猜你喜欢
  • 1970-01-01
  • 2022-01-07
  • 2013-06-28
  • 2012-06-17
  • 2019-05-14
  • 2021-12-04
  • 2015-03-04
  • 2020-05-01
相关资源
最近更新 更多