JavaFX-过滤组合框
我想要一个组合框,当用户键入时过滤列表项。其工作应如下:JavaFX-过滤组合框,javafx,combobox,filtering,Javafx,Combobox,Filtering,我想要一个组合框,当用户键入时过滤列表项。其工作应如下: 键入时,文本字段应显示一个可能的选择,但应突出显示用户尚未键入的部分 当他打开列表时,下拉菜单应该只显示可能的选项 在缩小可能的项目后,用户应使用箭头键选择剩余项目之一 过滤并不是那么重要,跳转到第一个匹配选择也可以 有类似的东西吗?我在类似的地方搜索了一会儿,发现了这个。 看一看: public class AutoCompleteComboBoxListener<T> implements EventHandler&l
- 键入时,文本字段应显示一个可能的选择,但应突出显示用户尚未键入的部分李>
- 当他打开列表时,下拉菜单应该只显示可能的选项
- 在缩小可能的项目后,用户应使用箭头键选择剩余项目之一
- 过滤并不是那么重要,跳转到第一个匹配选择也可以
有类似的东西吗?我在类似的地方搜索了一会儿,发现了这个。 看一看:
public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent> {
private ComboBox comboBox;
private StringBuilder sb;
private ObservableList<T> data;
private boolean moveCaretToPos = false;
private int caretPos;
public AutoCompleteComboBoxListener(final ComboBox comboBox) {
this.comboBox = comboBox;
sb = new StringBuilder();
data = comboBox.getItems();
this.comboBox.setEditable(true);
this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
comboBox.hide();
}
});
this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this);
}
@Override
public void handle(KeyEvent event) {
ListView lv = ((ComboBoxListViewSkin) comboBox.getSkin()).getListView();
if(event.getCode() == KeyCode.UP) {
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if(event.getCode() == KeyCode.DOWN) {
if(!comboBox.isShowing()) {
comboBox.show();
}
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if(event.getCode() == KeyCode.BACK_SPACE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
} else if(event.getCode() == KeyCode.DELETE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
}
if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
|| event.isControlDown() || event.getCode() == KeyCode.HOME
|| event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
return;
}
ObservableList list = FXCollections.observableArrayList();
for (int i=0; i<data.size(); i++) {
if(data.get(i).toString().toLowerCase().startsWith(
AutoCompleteComboBoxListener.this.comboBox
.getEditor().getText().toLowerCase())) {
list.add(data.get(i));
}
}
String t = comboBox.getEditor().getText();
comboBox.setItems(list);
comboBox.getEditor().setText(t);
if(!moveCaretToPos) {
caretPos = -1;
}
moveCaret(t.length());
if(!list.isEmpty()) {
comboBox.show();
}
}
private void moveCaret(int textLength) {
if(caretPos == -1) {
comboBox.getEditor().positionCaret(textLength);
} else {
comboBox.getEditor().positionCaret(caretPos);
}
moveCaretToPos = false;
}
}
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
public class FilterComboBox extends ComboBox<String> {
private ObservableList<String> initialList;
private ObservableList<String> bufferList = FXCollections.observableArrayList();
private String previousValue = "";
public FilterComboBox(ObservableList<String> items) {
super(items);
super.setEditable(true);
this.initialList = items;
this.configAutoFilterListener();
}
private void configAutoFilterListener() {
final FilterComboBox currentInstance = this;
this.getEditor().textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
previousValue = oldValue;
final TextField editor = currentInstance.getEditor();
final String selected = currentInstance.getSelectionModel().getSelectedItem();
if (selected == null || !selected.equals(editor.getText())) {
filterItems(newValue, currentInstance);
currentInstance.show();
if (currentInstance.getItems().size() == 1) {
setUserInputToOnlyOption(currentInstance, editor);
}
}
}
});
}
private void filterItems(String filter, ComboBox<String> comboBox) {
if (filter.startsWith(previousValue) && !previousValue.isEmpty()) {
ObservableList<String> filteredList = this.readFromList(filter, bufferList);
bufferList.clear();
bufferList = filteredList;
} else {
bufferList = this.readFromList(filter, initialList);
}
comboBox.setItems(bufferList);
}
private ObservableList<String> readFromList(String filter, ObservableList<String> originalList) {
ObservableList<String> filteredList = FXCollections.observableArrayList();
for (String item : originalList) {
if (item.toLowerCase().startsWith(filter.toLowerCase())) {
filteredList.add(item);
}
}
return filteredList;
}
private void setUserInputToOnlyOption(ComboBox<String> currentInstance, final TextField editor) {
final String onlyOption = currentInstance.getItems().get(0);
final String currentText = editor.getText();
if (onlyOption.length() > currentText.length()) {
editor.setText(onlyOption);
Platform.runLater(new Runnable() {
@Override
public void run() {
editor.selectRange(currentText.length(), onlyOption.length());
}
});
}
}
}
公共类AutoCompleteComboxListener实现EventHandler{
专用组合框组合框;
私家侦探;
私有可观测列表数据;
私有布尔值moveCaretToPos=false;
私人int caretPos;
公共自动完成组合框侦听器(最终组合框组合框){
this.comboBox=组合框;
sb=新的StringBuilder();
data=comboBox.getItems();
this.comboBox.setEditable(true);
this.comboBox.setOnKeyPressed(新的EventHandler(){
@凌驾
公共无效句柄(KeyEvent t){
comboBox.hide();
}
});
this.comboBox.setOnKeyReleased(autoCompleteComboxListener.this);
}
@凌驾
公共无效句柄(KeyEvent事件){
ListView lv=((ComboBoxListViewSkin)comboBox.getSkin()).getListView();
if(event.getCode()==KeyCode.UP){
caretPos=-1;
moveCaret(comboBox.getEditor().getText().length());
返回;
}else if(event.getCode()==KeyCode.DOWN){
如果(!comboBox.isShowing()){
comboBox.show();
}
caretPos=-1;
moveCaret(comboBox.getEditor().getText().length());
返回;
}else if(event.getCode()==KeyCode.BACK\u空格){
MoveCareTopos=真;
caretPos=comboBox.getEditor().getCaretPosition();
}else if(event.getCode()==KeyCode.DELETE){
MoveCareTopos=真;
caretPos=comboBox.getEditor().getCaretPosition();
}
如果(event.getCode()==KeyCode.RIGHT | | event.getCode()==KeyCode.LEFT
||event.isControlDown()| | event.getCode()==KeyCode.HOME
||event.getCode()==KeyCode.END | | event.getCode()==KeyCode.TAB){
返回;
}
ObservableList=FXCollections.observableArrayList();
对于(int i=0;i请看:
public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent> {
private ComboBox comboBox;
private StringBuilder sb;
private ObservableList<T> data;
private boolean moveCaretToPos = false;
private int caretPos;
public AutoCompleteComboBoxListener(final ComboBox comboBox) {
this.comboBox = comboBox;
sb = new StringBuilder();
data = comboBox.getItems();
this.comboBox.setEditable(true);
this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
comboBox.hide();
}
});
this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this);
}
@Override
public void handle(KeyEvent event) {
ListView lv = ((ComboBoxListViewSkin) comboBox.getSkin()).getListView();
if(event.getCode() == KeyCode.UP) {
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if(event.getCode() == KeyCode.DOWN) {
if(!comboBox.isShowing()) {
comboBox.show();
}
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if(event.getCode() == KeyCode.BACK_SPACE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
} else if(event.getCode() == KeyCode.DELETE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
}
if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
|| event.isControlDown() || event.getCode() == KeyCode.HOME
|| event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
return;
}
ObservableList list = FXCollections.observableArrayList();
for (int i=0; i<data.size(); i++) {
if(data.get(i).toString().toLowerCase().startsWith(
AutoCompleteComboBoxListener.this.comboBox
.getEditor().getText().toLowerCase())) {
list.add(data.get(i));
}
}
String t = comboBox.getEditor().getText();
comboBox.setItems(list);
comboBox.getEditor().setText(t);
if(!moveCaretToPos) {
caretPos = -1;
}
moveCaret(t.length());
if(!list.isEmpty()) {
comboBox.show();
}
}
private void moveCaret(int textLength) {
if(caretPos == -1) {
comboBox.getEditor().positionCaret(textLength);
} else {
comboBox.getEditor().positionCaret(caretPos);
}
moveCaretToPos = false;
}
}
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
public class FilterComboBox extends ComboBox<String> {
private ObservableList<String> initialList;
private ObservableList<String> bufferList = FXCollections.observableArrayList();
private String previousValue = "";
public FilterComboBox(ObservableList<String> items) {
super(items);
super.setEditable(true);
this.initialList = items;
this.configAutoFilterListener();
}
private void configAutoFilterListener() {
final FilterComboBox currentInstance = this;
this.getEditor().textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
previousValue = oldValue;
final TextField editor = currentInstance.getEditor();
final String selected = currentInstance.getSelectionModel().getSelectedItem();
if (selected == null || !selected.equals(editor.getText())) {
filterItems(newValue, currentInstance);
currentInstance.show();
if (currentInstance.getItems().size() == 1) {
setUserInputToOnlyOption(currentInstance, editor);
}
}
}
});
}
private void filterItems(String filter, ComboBox<String> comboBox) {
if (filter.startsWith(previousValue) && !previousValue.isEmpty()) {
ObservableList<String> filteredList = this.readFromList(filter, bufferList);
bufferList.clear();
bufferList = filteredList;
} else {
bufferList = this.readFromList(filter, initialList);
}
comboBox.setItems(bufferList);
}
private ObservableList<String> readFromList(String filter, ObservableList<String> originalList) {
ObservableList<String> filteredList = FXCollections.observableArrayList();
for (String item : originalList) {
if (item.toLowerCase().startsWith(filter.toLowerCase())) {
filteredList.add(item);
}
}
return filteredList;
}
private void setUserInputToOnlyOption(ComboBox<String> currentInstance, final TextField editor) {
final String onlyOption = currentInstance.getItems().get(0);
final String currentText = editor.getText();
if (onlyOption.length() > currentText.length()) {
editor.setText(onlyOption);
Platform.runLater(new Runnable() {
@Override
public void run() {
editor.selectRange(currentText.length(), onlyOption.length());
}
});
}
}
}
导入javafx.application.Platform;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.scene.control.ComboBox;
导入javafx.scene.control.TextField;
公共类筛选器ComboBox扩展组合框{
私人观察者初始列表;
私有ObservableList bufferList=FXCollections.observableArrayList();
私有字符串previousValue=“”;
公共过滤器通讯箱(可观察列表项){
超级(项目);
super.setEditable(true);
this.initialList=项目;
this.configAutoFilterListener();
}
私有void configAutoFilterListener(){
final FilterComboBox currentInstance=此;
this.getEditor().textProperty().addListener(新的ChangeListener()){
@凌驾
就下拉列表的筛选而言,public void已更改(ObservableValue。将可能选项列表包装在FilteredList
中不是最佳解决方案吗
MCVE:
导入javafx.application.application;
导入javafx.application.Platform;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.collections.transformation.FilteredList;
导入javafx.scene.scene;
导入javafx.scene.control.ComboBox;
导入javafx.scene.control.TextField;
导入javafx.scene.layout.HBox;
导入javafx.stage.stage;
公共类MCVE扩展应用程序{
公众假期开始(阶段){
HBox根=新的HBox();
ComboBox cb=新ComboBox();
cb.setEditable(true);
//创建一个包含一些虚拟值的列表。
ObservableList items=FXCollections.observableArrayList(“一”、“二”、“三”、“四”、“五”、“六”,
“七”、“八”、“九”、“十”);
//创建一个包装ObservableList的FilteredList。
FilteredList filteredItems=新的FilteredList(项目,p->true);
//将侦听器添加到组合框编辑器的textProperty
//每次更改输入时,侦听器都会简单地过滤列表
//只要用户没有选择列表中的项目。
cb.getEditor().textProperty().addListener((obs、oldValue、newValue)->{
final TextField editor=cb.getEditor();
最后选择的字符串=cb.getSelectionModel().getSelectedItem();
//这需要在GUI线程上运行,以避免所描述的错误
//在这里:https://bugs.openjdk.java.net/browse/JDK-8081700.
Platform.runLater(()->{
//如果未选择列表中的任何项目或选定的项目
//不等于当前输入,我们将重新筛选列表。
if(selected==null | |!selected.equals(editor.getText())){
filteredItems.setPredicate(项->{
//对于以
//与输入相同的字母。我们使用toUpperCase
//避免区分大小写。
if(item.toUpperCase().startsWith(newValue.toUpperCase())){
返回true;
}否则{
返回false;