具有历史功能的JavaFX可编辑ComboBox [英] JavaFX editable ComboBox with history function

查看:174
本文介绍了具有历史功能的JavaFX可编辑ComboBox的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个JavaFX ComboBox ,它会记住用户输入的条目的历史记录。添加新项目有效,但从下拉列表中选择不起作用。

I am attempting to make a JavaFX ComboBox that remembers the history of the entries entered by the user. Adding new items works, but selecting from the drop-down does not.

简而言之,我正在尝试将控件设置为

In a nutshell, I am trying to get the control to


  1. 将最近输入的条目添加到顶部,作为 ComboBox 的第一项。

  2. 清除下一个条目的 TextField 部分。

  3. ComboBox ,将选择复制到 TextField ,而不修改 ComboBox 的项目。

  1. Add the most recently typed entry to the top, as the first item of the ComboBox.
  2. Clear the TextField portion for the next entry.
  3. Upon selecting an item from the ComboBox, will copy selection to the TextField, without modifying the ComboBox's items.

添加新项目工作正常,复制之前的字段条目令人沮丧。

Adding new items works fine, it's the copying a previous entry to the field is proving frustrating.

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

The only similar problem I could find was javafx combobox items list issue, whose solution unfortunately did not fix my problem.

代码

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);
    }
}

谢谢!

推荐答案

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

Try the following updated HistoryField class. There are a couple of changes I made.

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

First of all, instead of passing a varargs of Strings, just pass the array you want. You can then convert the array to a List ready for the ComboBox using Arrays.asList() method.

此外,我简化了向列表中添加新项目的过程。监听器现在只会在列表中添加一个项目(如果它尚不存在)。

Also, I streamlined the process of adding a new item to the list. The listener will now only add an item to the list if it doesn't already exist.

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

You also never handled the max_size situation, so I added a simple check to remove the older entry once the max_size has been reached.

只有将项目添加到列表中时才会清除该字段;从你的问题中不清楚这是否是所希望的行为。

The field is only cleared if an item is added to the list; it is unclear from your question if that is the desired behavior.

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();
                }
            }
        });
    }
}

这篇关于具有历史功能的JavaFX可编辑ComboBox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆