问题
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
- Add the most recently typed entry to the top, as the first item of the
ComboBox. - Clear the
TextFieldportion for the next entry. - Upon selecting an item from the
ComboBox, will copy selection to theTextField, without modifying theComboBox's items.
Adding new items works fine, it's the copying a previous entry to the field is proving frustrating.
The only similar problem I could find was javafx combobox items list issue, whose solution unfortunately did not fix my problem.
Code
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();
}
});
}
}
Test class
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);
}
}
Thank you!
回答1:
Try the following updated HistoryField class. There are a couple of changes I made.
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.
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();
}
}
});
}
}
来源:https://stackoverflow.com/questions/51993138/javafx-editable-combobox-with-history-function