Skip to content

Instantly share code, notes, and snippets.

@floralvikings
Last active December 30, 2023 04:41
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save floralvikings/10290131 to your computer and use it in GitHub Desktop.
Save floralvikings/10290131 to your computer and use it in GitHub Desktop.
Simple JavaFX TextBox with AutoComplete functionality based on a supplied set.
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);
}
}
@Hariiharan1998
Copy link

There is an issue here, when we click on the empty space of the CustomMenuItem its not clickable, its clickable only if we click on the text in the CustomMenuItem. Any solution for this? I cannot use MenuItem only I can use CustomMenuItem because with CustomMenuItem i can highlight the entered text in the textfield, in list of customMenuItem. please suggest me some solution for this.

@nadavq
Copy link

nadavq commented May 1, 2023

Works amazing until today, i even used it from a kotlin class,
I implemented it like @EzequielAyzenberg mentioned

@GQ16
Copy link

GQ16 commented Dec 30, 2023

Thank you so much. I wasted hours trying to get the Gluon and ControlsFX AutoCompleteTextFields to work to no avail in Maven. This was so much easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment