第一次右键单击时,不会显示TableRow <object>上的上下文菜单

时间:2019-04-10 10:28:46

标签: javafx tableview javafx-8 contextmenu

因此,我遵循此示例,将上下文菜单与来自here的TableViews一起使用。我注意到使用此代码

row.contextMenuProperty().bind(Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));
第一次右键单击具有值的行时,不会显示

。我需要再次右键单击该行,以显示上下文菜单。我也尝试了这段代码(这是我的第一种方法,但是不再使用它,因为我在某个地方读到that指南是上下文菜单和表格视图相关内容的最佳/最佳实践),并且它显示了立即打开上下文菜单

if (row.getItem() != null) {
    rowMenu.show(row, event.getScreenX(), event.getScreenY());
}
else {
    // do nothing
}

但是我的这段代码问题是,每当我尝试右键单击没有数据的行时,它都会引发NullPointerException。

在右键单击后立即显示上下文菜单时,我应该怎么做才能防止NullPointerException?在我的代码中,我还有一个代码,根据绑定到行的myObject的属性,上下文菜单中的某个菜单项将被禁用,这就是为什么我需要上下文菜单立即弹出的原因。

我在第一段代码中也注意到了这一点。即使myObject的属性已经更改,它仍然具有启用/禁用的菜单项,除非我再次右键单击该行。我希望你能帮助我。谢谢!

这是MCVE:

public class MCVE_TableView extends Application{

@Override
public void start(Stage primaryStage) throws Exception {
    BorderPane myBorderPane = new BorderPane();
    TableView<People> myTable = new TableView<>();

    TableColumn<People, String> nameColumn = new TableColumn<>();
    TableColumn<People, Integer> ageColumn = new TableColumn<>();

    ContextMenu rowMenu = new ContextMenu();

    ObservableList<People> peopleList = FXCollections.observableArrayList();
    peopleList.add(new People("John Doe", 23));

    nameColumn.setMinWidth(100);
    nameColumn.setCellValueFactory(
        new PropertyValueFactory<>("Name"));

    ageColumn.setMinWidth(100);
    ageColumn.setCellValueFactory(
        new PropertyValueFactory<>("Age"));

    myTable.setItems(peopleList);
    myTable.getColumns().addAll(nameColumn, ageColumn);

    myTable.setRowFactory(tv -> {
        TableRow<People> row = new TableRow<>();

        row.setOnContextMenuRequested((event) -> {
            People selectedRow = row.getItem();
            rowMenu.getItems().clear();

            MenuItem sampleMenuItem = new MenuItem("Sample Button");
            if (selectedRow != null) {
                if (selectedRow.getAge() > 100) {
                    sampleMenuItem.setDisable(true);
                }

                rowMenu.getItems().add(sampleMenuItem);
            }
            else {
                event.consume();
            }

            /*if (row.getItem() != null) { // this block comment displays the context menu instantly
                rowMenu.show(row, event.getScreenX(), event.getScreenY());
            }
            else {
                // do nothing
            }*/

            // this requires the row to be right clicked 2 times before displaying the context menu
            row.contextMenuProperty().bind(Bindings.when(Bindings.isNotNull(row.itemProperty()))
            .then(rowMenu)
            .otherwise((ContextMenu)null));
        });

        return row;
    });

    myBorderPane.setCenter(myTable);

    Scene scene = new Scene(myBorderPane, 500, 500);
    primaryStage.setTitle("MCVE");
    primaryStage.setScene(scene);
    primaryStage.show();
}

public static void main (String[] args) {
    launch(args);
}

} 这是人民课

public class People {
SimpleStringProperty name;
SimpleIntegerProperty age;
public People(String name, int age) {
    this.name = new SimpleStringProperty(name);
    this.age = new SimpleIntegerProperty(age);
}

public SimpleStringProperty NameProperty() {
    return this.name;
}
public SimpleIntegerProperty AgeProperty() {
    return this.age;
}
public String getName() {
    return this.name.get();
}
public int getAge() {
    return this.age.get();
}

}

编辑:添加了MCVE

Edit2:更新了MCVE。仍然需要右键单击两次,然后弹出contextMenu

1 个答案:

答案 0 :(得分:2)

下面是一个代码段,以快速演示如何实例化/在何处实例化和配置每行ContextMenu。

  • 在行的实例化时间为每个TableRow创建一个ContextMenu / MenuItem
  • 创建一个条件绑定,如果不为空,则将菜单绑定到该行的contextMenuProperty(与您所做的相同)
  • 根据当前项目在onShowing处理程序中配置contextMenu(注意:无需防null,因为在这种情况下,条件绑定将隐式保证不显示菜单)

摘要:

myTable.setRowFactory(tv -> {
    TableRow<People> row = new TableRow<>() {
      ContextMenu rowMenu = new ContextMenu();
      MenuItem sampleMenuItem = new MenuItem("Sample Button");
      {
          rowMenu.getItems().addAll(sampleMenuItem);
          contextMenuProperty()
              .bind(Bindings
                  .when(Bindings.isNotNull(itemProperty()))
                  .then(rowMenu).otherwise((ContextMenu) null));
          rowMenu.setOnShowing(e -> {
              People selectedRow = getItem();
              sampleMenuItem.setDisable(selectedRow.getAge() > 100);
          });
      }

    };
    return row;
});