我正在为javafx寻找像select2这样的组件。
一个组合框,当弹出窗口出现时会有一个可搜索的文本字段,并在下面过滤了listview。
已经完成的任何想法或事情?
答案 0 :(得分:0)
我几个月前自己实现了这个。这个想法基本上就是将ComboBox
下拉列表包装在FilteredList
中,然后向ComboBox#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());
}
}
}