In the ComboBoxListViewSkin there is a key press handler added to the ListView that calls ComboBox.hide() when enter, escape or space is pressed. While enter and escape seem valid, space does not. I have an editable ComboBox that I want to drill down contents as text is typed in, ensuring the popup is displayed with matching items. If the complete list has items displayed with spaces you would want to type space - however this causes the call to hide(), making the popup collapse then re-expand. It's fine for any other text than space. The code that causes this is in ComboBoxListViewSkin.createListView(), and there doesn't appear to be any way to override or intercept this:
listView.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override public void handle(KeyEvent t) {
// TODO move to behavior, when (or if) this class becomes a SkinBase
if (t.getCode() == KeyCode.ENTER ||
t.getCode() == KeyCode.SPACE ||
t.getCode() == KeyCode.ESCAPE) {
comboBox.hide();
}
}
});
Example code showing this bug is listed below:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.SceneBuilder;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.FlowPaneBuilder;
import javafx.stage.Stage;
public class ComboBoxTest extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ObservableList<String> list = FXCollections.observableArrayList(
"aa a", "aab", "aa c",
"ab a", "abb", "ab c",
"ac a", "acb", "ac c",
"ba a", "bab", "ba c",
"bb a", "bbb", "bb c",
"bc a", "bcb", "bc c",
"ca a", "cab", "ca c",
"cb a", "cbb", "cb c",
"cc a", "ccb", "cc c");
FilterComboBox fcb = new FilterComboBox(list);
FlowPane pane = FlowPaneBuilder.create()
.padding(new Insets(10))
.children(fcb)
.build();
stage.setScene(SceneBuilder.create().root(pane).build());
stage.setResizable(true);
stage.show();
}
private class FilterComboBox extends ComboBox<String> {
private ObservableList<String> allItems;
private ObservableList<String> filteredItems = FXCollections.observableArrayList();
private String searchString = "";
FilterComboBox(ObservableList<String> allItems) {
super(allItems);
this.allItems = allItems;
setEditable(true);
setOnKeyReleased(new KeyHandler());
}
private class KeyHandler implements EventHandler<KeyEvent> {
@Override
public void handle(KeyEvent event) {
if (!event.getCode().isNavigationKey()) {
String newSearchString = getEditor().getText();
if(!searchString.equals(newSearchString)) {
processTextChanged(newSearchString);
}
}
}
private void processTextChanged(String newSearchString) {
searchString = newSearchString;
if(searchString.isEmpty()) {
setItems(allItems);
} else {
filteredItems.clear();
for (String item : allItems) {
if (item.startsWith(searchString)) {
filteredItems.add(item);
}
}
setItems(filteredItems);
}
show();
}
}
}
}
listView.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override public void handle(KeyEvent t) {
// TODO move to behavior, when (or if) this class becomes a SkinBase
if (t.getCode() == KeyCode.ENTER ||
t.getCode() == KeyCode.SPACE ||
t.getCode() == KeyCode.ESCAPE) {
comboBox.hide();
}
}
});
Example code showing this bug is listed below:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.SceneBuilder;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.FlowPaneBuilder;
import javafx.stage.Stage;
public class ComboBoxTest extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ObservableList<String> list = FXCollections.observableArrayList(
"aa a", "aab", "aa c",
"ab a", "abb", "ab c",
"ac a", "acb", "ac c",
"ba a", "bab", "ba c",
"bb a", "bbb", "bb c",
"bc a", "bcb", "bc c",
"ca a", "cab", "ca c",
"cb a", "cbb", "cb c",
"cc a", "ccb", "cc c");
FilterComboBox fcb = new FilterComboBox(list);
FlowPane pane = FlowPaneBuilder.create()
.padding(new Insets(10))
.children(fcb)
.build();
stage.setScene(SceneBuilder.create().root(pane).build());
stage.setResizable(true);
stage.show();
}
private class FilterComboBox extends ComboBox<String> {
private ObservableList<String> allItems;
private ObservableList<String> filteredItems = FXCollections.observableArrayList();
private String searchString = "";
FilterComboBox(ObservableList<String> allItems) {
super(allItems);
this.allItems = allItems;
setEditable(true);
setOnKeyReleased(new KeyHandler());
}
private class KeyHandler implements EventHandler<KeyEvent> {
@Override
public void handle(KeyEvent event) {
if (!event.getCode().isNavigationKey()) {
String newSearchString = getEditor().getText();
if(!searchString.equals(newSearchString)) {
processTextChanged(newSearchString);
}
}
}
private void processTextChanged(String newSearchString) {
searchString = newSearchString;
if(searchString.isEmpty()) {
setItems(allItems);
} else {
filteredItems.clear();
for (String item : allItems) {
if (item.startsWith(searchString)) {
filteredItems.add(item);
}
}
setItems(filteredItems);
}
show();
}
}
}
}
- relates to
-
JDK-8209991 Editable ComboBox: typing SPACE in textField must not hide popup
- Open