【问题标题】:JavaFX editable ComboBox with history function具有历史功能的 JavaFX 可编辑组合框
【发布时间】:2018-08-23 19:36:56
【问题描述】:

我正在尝试制作一个 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);
    }
}

谢谢!

【问题讨论】:

  • 你的问题是什么?您的代码涉及IndexOutOfBoundsException,但您的问题并未表明您是否遇到了麻烦。究竟什么不起作用?
  • @zephyr 这正是我所期望的应用选择然后“重置”ComboBox 即退出编辑模式以便可以再次添加新条目。因为它在if-block 的第一部分起作用。

标签: java javafx combobox


【解决方案1】:

尝试以下更新的HistoryField 类。我做了一些更改。

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

此外,我还简化了向列表中添加新项目的过程。侦听器现在只会在列表不存在的情况下将其添加到列表中。

您也从未处理过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();
                }
            }
        });
    }
}

【讨论】:

  • 谢谢!但是使用您的代码,如何将所选项目应用于文本字段并添加一些内容?当我添加一些项目,然后单击一个项目时,它不允许我添加任何其他项目。例如。给定列表“alpha”、“beta”、“gamma”,如果我选择“beta”,我不能删除它并添加“delta”
  • 这样做的原因是,如果oldValue == null,您最初只允许附加项目。请参阅我删除if 语句的那部分的编辑。您现在可以进行更改了。
  • 如果您希望能够通过在其上键入来删除“测试版”,这将需要更多处理并且更适合新问题。
  • 没有必要更改构造函数的签名 - getItems().setAll(strings) 会很好,没有不相关的代码行。 @SKNB 不太明白为什么要为这些项目保留别名?历史只是使代码复杂化,而我没有看到任何好处;)
  • @zephyr 谢谢!这很好地解决了问题。我唯一的另一个问题是添加重复的项目,例如如果用户先输入了“foo”和“bar”,他应该可以再次输入“foo”。那么它将是“foo”“bar”“foo”。但我认为你给了我足够多的东西让我现在继续。再次感谢
猜你喜欢
  • 2015-10-07
  • 2014-07-21
  • 1970-01-01
  • 2021-05-09
  • 1970-01-01
  • 2012-12-03
  • 1970-01-01
  • 2018-01-08
  • 2014-10-23
相关资源
最近更新 更多