具有历史功能的JavaFX可编辑ComboBox

时间:2018-08-23 19:36:56

标签: java javafx combobox

我正在尝试制作一个JavaFX ComboBox来记住用户输入的条目的历史记录。添加新项目有效,但是从下拉菜单中选择无效。

简而言之,我试图将控件

  1. 将最新输入的条目添加到顶部,作为ComboBox的第一项。
  2. 清除TextField部分以保留下一个条目。
  3. ComboBox中选择一个项目后,会将选择内容复制到TextField,而无需修改ComboBox的项目。

添加新项目效果很好,这是将先前的条目复制到该字段的过程令人沮丧。

我唯一能找到的类似问题是javafx combobox items list issue,很遗憾,该解决方案无法解决我的问题。

代码

import java.util.LinkedList;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;


public class HistoryField<String> extends ComboBox<String> {
    public final static int DEFAULT_MAX_ENTRIES = 256;

    //Data members
    private int maxSize;
    private final ObservableList<String> history;

   //Default constructor
    public HistoryField() {
        this(DEFAULT_MAX_ENTRIES, (String[]) null);
    }

    public HistoryField(int maxSize, String ... entries) {
        super(FXCollections.observableList(new LinkedList<>()));
        this.setEditable(true);

        this.maxSize = maxSize;
        this.history = this.getItems();


        //Populate list with entries (if any)
        if (entries != null) {
            for (int i = 0; ((i < entries.length) && (i < this.maxSize)); i++) {
                this.history.add(entries[i]);
            }
         }

        this.valueProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
            if ((oldValue == null) && (newValue != null)) {                
                if (this.getSelectionModel().getSelectedIndex() < 0) {
                    this.getItems().add(0, newValue);
                    this.getSelectionModel().clearSelection();
                }
            } else {

                //This throws IndexOutOfBoundsException
                this.getSelectionModel().clearSelection();
            }
        });
    }
}

测试类

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class HistoryFieldTest extends Application {
    private HistoryField<String> historyField;

    @Override
    public void start(Stage primaryStage) {        
        this.historyField = new HistoryField<>();

        BorderPane root = new BorderPane();
        root.setBottom(historyField);

        Scene scene = new Scene(root, 300, 250);
        primaryStage.setTitle("History Field Test");
        primaryStage.setScene(scene);

        primaryStage.show();
    }

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

谢谢!

1 个答案:

答案 0 :(得分:0)

尝试以下更新的HistoryField类。我做了几处更改。

首先,不要传递varargs的字符串,只需传递所需的数组即可。然后,您可以使用List方法将数组转换为ComboBox,准备好Arrays.asList()

我还简化了将新项目添加到列表的过程。现在,侦听器只会将尚不存在的项目添加到列表中。

您也从未处理过max_size的情况,因此我添加了一个简单的检查,以在达到max_size后删除较旧的条目。

仅当将项目添加到列表时,才清除该字段;从您的问题尚不清楚这是否是所需的行为。

public class HistoryField extends ComboBox<String> {

    private final static int DEFAULT_MAX_ENTRIES = 5;

    //Data members
    private int maxSize;
    private final ObservableList<String> history;

    //Default constructor
    public HistoryField() {
        this(DEFAULT_MAX_ENTRIES, null);
    }

    /* Changed parameter to an array instead of list of Strings */
    public HistoryField(int maxSize, String[] entries) {
        this.setEditable(true);

        this.maxSize = maxSize;

        /* Convert the passed array to a list and populate the dropdown */
        if (entries != null) {
            history = FXCollections.observableArrayList(Arrays.asList(entries));
        } else {
            history = FXCollections.observableArrayList();
        }

        setItems(history);

        this.valueProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {

                // Check if value already exists in list
                if (!this.history.contains(newValue)) {
                    this.history.add(0, newValue);

                    // If the max_size has been reached, remove the oldest item from the list
                    if (this.history.size() > maxSize) {
                        this.history.remove(history.size() - 1);
                    }

                    System.out.println(history);

                    // Clear the selection when new item is added
                    this.getSelectionModel().clearSelection();
                }
            }
        });
    }
}