JavaFX可搜索组合框(如js select2)

JavaFX可搜索组合框(如js select2),javafx,Javafx,我正在寻找一个类似JavaFX的组件 一个组合框,当弹出窗口出现并在下面过滤列表视图时,它将有一个可搜索的文本字段 有什么想法或已经做过的事情吗?几个月前我自己就实现了。基本上,您可以将组合框下拉列表包装在FilteredList中,然后将侦听器添加到组合框#textProperty(),以更改FilteredList的谓词 我的类包含很多额外的功能,例如将小写输入转换为大写输入的选项,以及限制输入的长度。如果你不需要这些部件,你可以把它们取下来 import javafx.applicatio

我正在寻找一个类似JavaFX的组件

一个
组合框
,当弹出窗口出现并在下面过滤
列表视图时,它将有一个可搜索的
文本字段


有什么想法或已经做过的事情吗?

几个月前我自己就实现了。基本上,您可以将
组合框
下拉列表包装在
FilteredList
中,然后将侦听器添加到
组合框#textProperty()
,以更改
FilteredList
的谓词

我的类包含很多额外的功能,例如将小写输入转换为大写输入的选项,以及限制输入的长度。如果你不需要这些部件,你可以把它们取下来

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class MCVE extends Application {

    @Override
    public void start(Stage stage) {
        ComboBox<String> box = new ComboBox<String>();
        box.setEditable(true);

        // For the combo box filter to work properly we need to create the item
        // list and wrap it in a FilteredList.
        ObservableList<String> items = FXCollections.observableArrayList("One", "Two", "Three", "OneTwo", "ThreeTwo",
                "OneTwoThree");
        FilteredList<String> filteredItems = new FilteredList<String>(items);

        // Then you need to provide the InputFilter with the FilteredList in the
        // constructor call.
        box.getEditor().textProperty().addListener(new InputFilter(box, filteredItems, false));

        box.setItems(filteredItems);

        BorderPane view = new BorderPane();
        view.setCenter(box);

        stage.setScene(new Scene(view));
        stage.show();
    }

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

    /**
     * 
     * @author Jonatan Stenbacka
     *
     */
    class InputFilter implements ChangeListener<String> {

        private ComboBox<String> box;
        private FilteredList<String> items;
        private boolean upperCase;
        private int maxLength;
        private String restriction;

        /**
         * @param box
         *            The combo box to whose textProperty this listener is
         *            added.
         * @param items
         *            The {@link FilteredList} containing the items in the list.
         */
        public InputFilter(ComboBox<String> box, FilteredList<String> items, boolean upperCase, int maxLength,
                String restriction) {
            this.box = box;
            this.items = items;
            this.upperCase = upperCase;
            this.maxLength = maxLength;
            this.restriction = restriction;
        }

        public InputFilter(ComboBox<String> box, FilteredList<String> items, boolean upperCase, int maxLength) {
            this(box, items, upperCase, maxLength, null);
        }

        public InputFilter(ComboBox<String> box, FilteredList<String> items, boolean upperCase) {
            this(box, items, upperCase, -1, null);
        }

        public InputFilter(ComboBox<String> box, FilteredList<String> items) {
            this(box, items, false);
        }

        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            StringProperty value = new SimpleStringProperty(newValue);

            // If any item is selected we save that reference.
            String selected = box.getSelectionModel().getSelectedItem() != null
                    ? box.getSelectionModel().getSelectedItem() : null;

            String selectedString = null;
            // We save the String of the selected item.
            if (selected != null) {
                selectedString = (String) selected;
            }

            if (upperCase) {
                value.set(value.get().toUpperCase());
            }

            if (maxLength >= 0 && value.get().length() > maxLength) {
                value.set(oldValue);
            }

            if (restriction != null) {
                if (!value.get().matches(restriction + "*")) {
                    value.set(oldValue);
                }
            }

            // If an item is selected and the value in the editor is the same
            // as the selected item we don't filter the list.
            if (selected != null && value.get().equals(selectedString)) {
                // This will place the caret at the end of the string when
                // something is selected.
                Platform.runLater(() -> box.getEditor().end());
            } else {
                items.setPredicate(item -> {
                    String itemString = item;
                    if (itemString.toUpperCase().contains(value.get().toUpperCase())) {
                        return true;
                    } else {
                        return false;
                    }
                });
            }

            // If the popup isn't already showing we show it.
            if (!box.isShowing()) {
                // If the new value is empty we don't want to show the popup,
                // since
                // this will happen when the combo box gets manually reset.
                if (!newValue.isEmpty() && box.isFocused()) {
                    box.show();
                }
            }
            // If it is showing and there's only one item in the popup, which is
            // an
            // exact match to the text, we hide the dropdown.
            else {
                if (items.size() == 1) {
                    // We need to get the String differently depending on the
                    // nature
                    // of the object.
                    String item = items.get(0);

                    // To get the value we want to compare with the written
                    // value, we need to crop the value according to the current
                    // selectionCrop.
                    String comparableItem = item;

                    if (value.get().equals(comparableItem)) {
                        Platform.runLater(() -> box.hide());
                    }
                }
            }

            box.getEditor().setText(value.get());
        }
    }
}
导入javafx.application.application;
导入javafx.application.Platform;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.collections.transformation.FilteredList;
导入javafx.scene.scene;
导入javafx.scene.control.ComboBox;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
公共类MCVE扩展应用程序{
@凌驾
公众假期开始(阶段){
ComboBox=新的ComboBox();
box.setEditable(true);
//为了使组合框过滤器正常工作,我们需要创建该项
//列出并将其包装在FilteredList中。
ObservableList items=FXCollections.observableArrayList(“一”、“二”、“三”、“一二”、“三二”,
“一对三”);
FilteredList filteredItems=新的FilteredList(项目);
//然后,您需要在中为InputFilter提供FilteredList
//构造函数调用。
box.getEditor().textProperty().addListener(新的InputFilter(box,filteredItems,false));
框。设置项(过滤项);
BorderPane视图=新建BorderPane();
视图。设置中心(框);
舞台场景(新场景(视图));
stage.show();
}
公共静态void main(字符串[]args){
发射();
}
/**
* 
*@作者Jonatan Stenbacka
*
*/
类InputFilter实现ChangeListener{
私人组合框;
私人筛选列表项目;
私有布尔大写;
私有整数最大长度;
私有字符串限制;
/**
*@param-box
*此侦听器指向其textProperty的组合框
*补充说。
*@param项目
*包含列表中项目的{@link FilteredList}。
*/
公共InputFilter(组合框、FilteredList项、布尔大写、int maxLength、,
字符串限制){
this.box=box;
这个项目=项目;
this.upperCase=大写;
this.maxLength=maxLength;
这个限制=限制;
}
公共InputFilter(组合框,FilteredList项,布尔大写,int maxLength){
这(框、项、大写、maxLength、null);
}
公共InputFilter(组合框,FilteredList项,布尔大写){
这(框,项,大写,-1,空);
}
公共输入筛选器(组合框、筛选器列表项){
此(框、项、假);
}
@凌驾
公共无效已更改(可观察值)