Контекстное меню в TableRow <Object>не отображается при первом щелчке правой кнопкой мыши - PullRequest
1 голос
/ 10 апреля 2019

Таким образом, я следовал этому примеру при использовании контекстного меню с TableViews от здесь . Я заметил, что с помощью этого кода

row.contextMenuProperty().bind(Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));

не отображается при первом щелчке правой кнопкой мыши по строке со значениями. Мне нужно снова щелкнуть правой кнопкой мыши по этой строке, чтобы появилось контекстное меню. Я также попробовал этот код (это мой первый подход, но я его больше не использую, потому что я где-то читал, что руководство , которое является лучшей / хорошей практикой для всего, что связано с контекстным меню и просмотром таблицы), и оно немедленно отображает контекстное меню

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 Ответ

2 голосов
/ 10 апреля 2019

Ниже приведен фрагмент кода для быстрой демонстрации того, как и где создавать экземпляры и настраивать контекстное меню для каждой строки. Это

  • создает ContextMenu / MenuItem для каждой TableRow во время создания строки
  • создает условную привязку, которая связывает меню со строкой contextMenuProperty, если не пусто (точно так же, как вы сделали)
  • настраивает contextMenu в обработчике onShowing, в зависимости от текущего элемента (примечание: нет необходимости в защите от 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;
}); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...