-
Bug
-
Resolution: Fixed
-
P4
-
jfx11, jfx14
Use-case is to let F4 trigger a process different from opening the popup (see https://stackoverflow.com/q/58550028/203657 - which might be a bad idea as for ux ;). Typically, such a requirement can be implemented by registering an eventFilter on the combo, do custom stuff and consume the event.
For combo and related, that's not possible because popupControl uses the F4 to toggle the popup internally (no way to override/customize)
// called by an eventFilter registered for type KeyEvent.ANY
private void handleKeyEvent(KeyEvent ke, boolean doConsume) {
...
} else if (ke.getCode() == KeyCode.F4) {
if (ke.getEventType() == KeyEvent.KEY_RELEASED) {
if (comboBoxBase.isShowing()) comboBoxBase.hide();
else comboBoxBase.show();
}
ke.consume(); // we always do a consume here (otherwise unit tests fail)
...
On digging a bit, it looks like a left-over from pre-inputMap times: ComboBoxBaseBehavior has a keyMapping for F4 for doing the same. So the offending code block in popupControl can probably simply be removed.
For convenience, a short example demonstrating the issue: compile, run
- press F4 in any of the controls
- expected: printout only
- actual: printout only and popup toggled
Note that the exact behavior depends on type of combo and its editable state
ComboBox: misbehaves for not-editable, okay for editable
DatePicker: never misbehaves
ColorPicker: always misbehaves
public class ComboAlikeKeyHandling extends Application {
private Parent createContent() {
ComboBox<String> combo = new ComboBox<>();
combo.getItems().addAll("one", "two");
ComboBox<String> comboEditable = new ComboBox<>();
comboEditable.getItems().addAll("one", "two");
comboEditable.setEditable(true);
DatePicker picker = new DatePicker();
picker.setEditable(false);
DatePicker pickerEditable = new DatePicker();
ColorPicker color = new ColorPicker();
ColorPicker colorEditable = new ColorPicker();
colorEditable.setEditable(true);
EventHandler<KeyEvent> grabF4 = e -> {
if (e.getCode() == KeyCode.F4) {
System.out.println("my own F4 handling");
e.consume();
}
};
combo.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
comboEditable.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
picker.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
pickerEditable.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
color.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
colorEditable.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
VBox box = new VBox(10, combo, comboEditable, picker, pickerEditable, color, colorEditable);
return box;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent(), 200, 200));
stage.setTitle("");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
For combo and related, that's not possible because popupControl uses the F4 to toggle the popup internally (no way to override/customize)
// called by an eventFilter registered for type KeyEvent.ANY
private void handleKeyEvent(KeyEvent ke, boolean doConsume) {
...
} else if (ke.getCode() == KeyCode.F4) {
if (ke.getEventType() == KeyEvent.KEY_RELEASED) {
if (comboBoxBase.isShowing()) comboBoxBase.hide();
else comboBoxBase.show();
}
ke.consume(); // we always do a consume here (otherwise unit tests fail)
...
On digging a bit, it looks like a left-over from pre-inputMap times: ComboBoxBaseBehavior has a keyMapping for F4 for doing the same. So the offending code block in popupControl can probably simply be removed.
For convenience, a short example demonstrating the issue: compile, run
- press F4 in any of the controls
- expected: printout only
- actual: printout only and popup toggled
Note that the exact behavior depends on type of combo and its editable state
ComboBox: misbehaves for not-editable, okay for editable
DatePicker: never misbehaves
ColorPicker: always misbehaves
public class ComboAlikeKeyHandling extends Application {
private Parent createContent() {
ComboBox<String> combo = new ComboBox<>();
combo.getItems().addAll("one", "two");
ComboBox<String> comboEditable = new ComboBox<>();
comboEditable.getItems().addAll("one", "two");
comboEditable.setEditable(true);
DatePicker picker = new DatePicker();
picker.setEditable(false);
DatePicker pickerEditable = new DatePicker();
ColorPicker color = new ColorPicker();
ColorPicker colorEditable = new ColorPicker();
colorEditable.setEditable(true);
EventHandler<KeyEvent> grabF4 = e -> {
if (e.getCode() == KeyCode.F4) {
System.out.println("my own F4 handling");
e.consume();
}
};
combo.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
comboEditable.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
picker.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
pickerEditable.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
color.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
colorEditable.addEventFilter(KeyEvent.KEY_RELEASED, grabF4);
VBox box = new VBox(10, combo, comboEditable, picker, pickerEditable, color, colorEditable);
return box;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent(), 200, 200));
stage.setTitle("");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}