2015-12-10 3 views
1

У меня есть требование перемещаться по таблице, когда пользователь нажимает клавишу ENTER. Для этого я создал фильтр событий, похожий на:KeyEvent on Dialog не используется при закрытии в JavaFX

private EventHandler<KeyEvent> keyReleasedFilter = event -> { 
    if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) { 
     previousPosition = table.getFocusModel().getFocusedCell(); 
     //do my navigation 
    } 
} 

я столкнулся с проблемой, когда JavaFX Modal Dialogs, используемой во время навигации таблицы, чтобы указать ошибку, вызывают проблемы с этим фильтром. Если пользователь закрыл диалог с помощью клавиши ENTER, это событие попадает в ловушку моего фильтра событий на родительском этапе. Я не знаю, как это предотвратить. Это вызывает непоследовательную навигацию.

Вот простое приложение, которое демонстрирует поведение:

public void start(Stage primaryStage) { 
    final Alert d = new Alert(Alert.AlertType.ERROR); 
    d.initModality(Modality.WINDOW_MODAL); 

    Button btn = new Button(); 
    btn.setText("Say 'Hello World'"); 
    btn.addEventFilter(KeyEvent.KEY_RELEASED, event -> { 
     if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) { 
      d.showAndWait(); 
     } 
    }); 

    Scene scene = new Scene(new StackPane(btn), 300, 250); 

    primaryStage.setTitle("Hello World!"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 

Я заметил, что диалог будет закрыт с KEY_PRESSED события, а не захватит KEY_RELEASED события.

Я попытался добавить фильтр событий в диалог (Button/DialogPane/Scene и даже Stage) - никто не перехватывает событие KEY_RELEASED.

Спасибо.

+0

Я попытался использовать event.consume() на dialog.setOnHidden(), но это тоже не работает. –

ответ

1

Если нет другой причины, чтобы использовать KEY_RELEASED событие, то я бы рекомендовал переход на запуск по KEY_PRESSED для навигации, а и переключить EventFilter на EventHandler. В приведенном ниже примере вы можете включать и выключать Alert. Когда он будет включен, вы заметите, что текст кнопки не изменяется. Когда он выключится, текст кнопки изменится. Посмотрите, как JavaFX создает цепочки событий here, если вы еще этого не сделали.

boolean error = false; 
int i = 0; 

@Override 
public void start(Stage primaryStage) 
{ 
    final Alert d = new Alert(Alert.AlertType.ERROR); 
    d.initModality(Modality.WINDOW_MODAL); 

    Button err = new Button(); 
    err.setText("Error off"); 
    err.addEventHandler(ActionEvent.ACTION, t -> 
    { 
     error = !error; 
     if (error) 
      err.setText("Error on"); 
     else 
      err.setText("Error off"); 
    }); 

    Button btn = new Button(); 
    btn.setText("Say 'Hello World'"); 

    btn.addEventHandler(KeyEvent.KEY_PRESSED, event -> 
    { 
     if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) { 
      if (error) 
      { 
       d.showAndWait(); 
      } 
      else 
      { 
       i++; 
       btn.setText(String.valueOf(i)); 
      } 
     } 
    }); 


    Scene scene = new Scene(new VBox(btn, err), 300, 250); 

    primaryStage.setTitle("Hello World!"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 
+0

К сожалению, мне нужен KEY_RELEASED, чтобы все произошло правильно. По какой-то причине, когда я использую KEY_PRESSED (я начал с этого), я не получаю навигацию, как хотелось бы. Я сделаю снимок с обработчиком событий, а не фильтром, и посмотрю, устраняет ли это проблему. Но просто переход к обработчику не сделал. –

+0

Я изменил все, чтобы использовать KEY_PRESSED, а не KEY_RELEASED, и editCommit, похоже, срабатывает дважды, когда у меня есть ошибка, и я получу два диалога. Вот почему я использовал KEY_RELEASED, так как я не получаю этого поведения, но у меня происходит откат KEY_RELEASED. –

+0

Я считаю, что я определил причину проблем editCommit и почему их вызывали дважды. Я исправил это и вернулся к KEY_PRESSED и, похоже, работает. Это потребует дальнейшего тестирования. Но я думаю, что я на правильном пути. Благодарю. –

0

Так у меня есть хак, который работает - я действительно не нравится, так что я надеюсь, что есть лучшее решение (чистый один), чтобы решить эту проблему ....

В принципе, правильно прежде чем я открою свой диалог, я установил логическое значение, чтобы я знал, что он открыт. Затем в моем фильтре событий выпустите, если для него установлено значение true.

общественного класса EventTester расширяет приложение {

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

private boolean modalWasShowing = false; 
@Override 
public void start(Stage primaryStage) { 
    final Alert d = new Alert(Alert.AlertType.ERROR); 
    d.initModality(Modality.WINDOW_MODAL); 

    Button btn = new Button(); 
    btn.setText("Say 'Hello World'"); 
    btn.addEventFilter(KeyEvent.KEY_RELEASED, event -> { 
     if(modalWasShowing){ 
      modalWasShowing=false; 
      return; 
     } 
     if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) { 
      modalWasShowing = true; 
      d.showAndWait(); 
     } 
    }); 

    Scene scene = new Scene(new StackPane(btn), 300, 250); 

    primaryStage.setTitle("Hello World!"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 

Пожалуйста, дайте мне знать, если вы знаете лучший способ справиться с этим.

Смежные вопросы