在 FXML 中定义 TableView onMousePressed 操作

Defining TableView onMousePressed actions in FXML

我有一个正在处理的 Java 项目,它使用 JavaFX 生成 UI。我不是一个 Java 程序员(一般来说不是一个程序员 - 我是 CS 学生),所以这是一种学习经验,但通常我会在回答我自己的问题时去。不过,我现在遇到了 TableView 的棘手问题,有点迷路了 - 具体来说,我似乎无法设置任何类型的操作来响应与 TableView 的交互。

我项目的当前布局是 Main.java、Controller.java 和 UI.fxml。在 Main 中,pane/scene 在程序启动时从 UI.fxml 加载。 (从技术上讲,该项目包含其他几个代码位,但我只尝试 post 相关的内容。)我在 UI.fxml 中定义了一个 TableView,如下所示:

<TableView fx:id="queueTable">
    <columns>
        <TableColumn text="Title">
             <cellValueFactory>
                <PropertyValueFactory property="tableTitle"/>
            </cellValueFactory>
        </TableColumn>
        <TableColumn text="Artist">
            <cellValueFactory>
                <PropertyValueFactory property="tableArtist"/>
            </cellValueFactory>
        </TableColumn>
        <TableColumn text="Album">
        <cellValueFactory>
                <PropertyValueFactory property="tableAlbum"/>
            </cellValueFactory>
        </TableColumn>
    </columns>
</TableView>

同样,我在 UI.fxml 中使用 onAction 定义了几个按钮:

<Button fx:id="buttonQueueAdd" text="Add" onAction="#addMediaToQueue"/>

在我之前的代码中,我能够在生成 TableView 的方法中为选择 TableView 中的项目定义一个事件。但是,现在所有 UI 创建都是通过 FXML 文件完成的。 FXML 文件有一个控制器 class 它引用 (Controller.java),其中为各种按钮定义了所有操作,但我似乎无法让它接受任何属性,如 [=12] =]、setOnMousePressed 等在 TableView 的 FXML 文件中,就像它接受 Button 的 'onAction' 属性一样。

看来我可以通过在 Main class 中定义操作(或在 Controller class 中创建一个在 Main class 中调用的方法来获得解决方法,当创建场景时),但这将不起作用,除非我在我的控制器 class 中使 queueTable 静态......然后打破所有操作 TableView 中项目的功能 - 例如,我无法再向 TableView/the 添加项目 UI 不刷新以显示项目已添加。

似乎最好的解决方案是不在 FXML 中创建 TableView,而是在 FXML 文件之外创建 TableView 及其所有 onMousePressed 事件等,并将它们添加到场景中我的 Main class 的 start 方法。以前就是这样做的,当时效果还可以。然而,这看起来很混乱,并导致我的 UI 元素散布在多个 classes and/or FXML 文件中 - 这是我正在与其他几个学生合作的项目,并且我尽量保持一切 streamlined/organized。我是必须硬着头皮按照 "messy" 的方式去做,还是有更好的选择?

您仍然可以使用 fxml 生成 TableView,但要向控制器添加 initialize 方法。此方法在创建对象结构后由 FXMLLoader 调用,可用于对对象结构进行修改,而这在 fxml 中是做不到的:

@FXML
private void initialize() {
    queueTable.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
        ...
    });
}

如果您需要从 Main 添加此侦听器,您可以向控制器添加一个方法并从用于创建 fxml 的 FXMLLoader 实例获取控制器。

控制器

public void addSelectedIndexListener(ChangeListener<? super Number> listener) {
    queueTable.getSelectionModel().selectedIndexProperty().addListener(listener);
}

主要

FXMLLoader loader = new FXMLLoader(fxmlUrl);
myNode = loader.load();
Controller controller = loader.getController();
controller.addSelectedIndexListener((observable, oldValue, newValue) -> {
    ...
});

注意是一个属性 属性 应该取决于一个属性 的选择模型,你也许可以使用expression binding 来达到想要的效果。

<BorderPane xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
    <center>
        <TableView fx:id="table" BorderPane.alignment="CENTER">
            <columns>
                <TableColumn text="value">
                    <cellValueFactory>
                        <PropertyValueFactory property="value"/>
                    </cellValueFactory>
                </TableColumn>
            </columns>
            <items>
                <FXCollections fx:factory="observableArrayList">
                    <Item value="Hello World"/>
                    <Item value="42"/>
                </FXCollections>
            </items>
        </TableView>
    </center>
    <left>
        <Button mnemonicParsing="false" text="Remove" BorderPane.alignment="CENTER" disable="${table.selectionModel.selectedIndex+0&lt;0}" />
    </left>
</BorderPane>

请注意,table.selectionModel.selectedIndex+0<0 部分是一种变通方法,因为 JavaFX 当前不使用 null-安全相等性检查(table.selectionModel.selectedItem==null 不起作用)并且无法获取用于比较的 0 常量的类型 (table.selectionModel.selectedIndex<0),因此目前这似乎不是一个好的选择。