Forked from floralvikings/AutoCompleteTextBox.java
Created
February 26, 2018 23:19
-
-
Save firephil/4c91ee2729b5b3732c7e8b7e9a4513f0 to your computer and use it in GitHub Desktop.
Simple JavaFX TextBox with AutoComplete functionality based on a supplied set.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javafx.beans.value.ChangeListener; | |
import javafx.beans.value.ObservableValue; | |
import javafx.event.ActionEvent; | |
import javafx.event.EventHandler; | |
import javafx.geometry.Side; | |
import javafx.scene.control.ContextMenu; | |
import javafx.scene.control.CustomMenuItem; | |
import javafx.scene.control.Label; | |
import javafx.scene.control.TextField; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.SortedSet; | |
import java.util.TreeSet; | |
/** | |
* This class is a TextField which implements an "autocomplete" functionality, based on a supplied list of entries. | |
* @author Caleb Brinkman | |
*/ | |
public class AutoCompleteTextField extends TextField | |
{ | |
/** The existing autocomplete entries. */ | |
private final SortedSet<String> entries; | |
/** The popup used to select an entry. */ | |
private ContextMenu entriesPopup; | |
/** Construct a new AutoCompleteTextField. */ | |
public AutoCompleteTextField() { | |
super(); | |
entries = new TreeSet<>(); | |
entriesPopup = new ContextMenu(); | |
textProperty().addListener(new ChangeListener<String>() | |
{ | |
@Override | |
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) { | |
if (getText().length() == 0) | |
{ | |
entriesPopup.hide(); | |
} else | |
{ | |
LinkedList<String> searchResult = new LinkedList<>(); | |
searchResult.addAll(entries.subSet(getText(), getText() + Character.MAX_VALUE)); | |
if (entries.size() > 0) | |
{ | |
populatePopup(searchResult); | |
if (!entriesPopup.isShowing()) | |
{ | |
entriesPopup.show(AutoCompleteTextField.this, Side.BOTTOM, 0, 0); | |
} | |
} else | |
{ | |
entriesPopup.hide(); | |
} | |
} | |
} | |
}); | |
focusedProperty().addListener(new ChangeListener<Boolean>() { | |
@Override | |
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean aBoolean2) { | |
entriesPopup.hide(); | |
} | |
}); | |
} | |
/** | |
* Get the existing set of autocomplete entries. | |
* @return The existing autocomplete entries. | |
*/ | |
public SortedSet<String> getEntries() { return entries; } | |
/** | |
* Populate the entry set with the given search results. Display is limited to 10 entries, for performance. | |
* @param searchResult The set of matching strings. | |
*/ | |
private void populatePopup(List<String> searchResult) { | |
List<CustomMenuItem> menuItems = new LinkedList<>(); | |
// If you'd like more entries, modify this line. | |
int maxEntries = 10; | |
int count = Math.min(searchResult.size(), maxEntries); | |
for (int i = 0; i < count; i++) | |
{ | |
final String result = searchResult.get(i); | |
Label entryLabel = new Label(result); | |
CustomMenuItem item = new CustomMenuItem(entryLabel, true); | |
item.setOnAction(new EventHandler<ActionEvent>() | |
{ | |
@Override | |
public void handle(ActionEvent actionEvent) { | |
setText(result); | |
entriesPopup.hide(); | |
} | |
}); | |
menuItems.add(item); | |
} | |
entriesPopup.getItems().clear(); | |
entriesPopup.getItems().addAll(menuItems); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment