Auto Complete ComboBox 2
//package util.autocomplete;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicComboBoxEditor;
/**
* This class uses AutoCompleteComboBoxEditor and AutoCompleteTextField to
* offer and Auto Completion to typed text based on the Objects added to the
* ComboBox.
* ** IMPORTANT **
* Since this is a text-based utility any Object added to this ComboBox (even
* those that you create) MUST, I repeat MUST have a valid toString method that
* returns the portion text representation of your
* @author Brandon Buck
* @version 1.0
*/
public class AutoCompleteComboBox<E> extends JComboBox {
private AutoCompleteTextField editorComp;
public AutoCompleteComboBox() {
super();
AutoCompleteComboBoxEditor cbe = new AutoCompleteComboBoxEditor();
this.editorComp = (AutoCompleteTextField)(cbe.getEditorComponent());
this.setEditor(cbe);
this.setEditable(true);
}
@Override
public void addItem(Object anObject) {
super.addItem(anObject);
editorComp.addPossibility(anObject.toString());
}
@Override
public void removeAllItems() {
super.removeAllItems();
editorComp.removeAllPossibilities();
}
public AutoCompleteTextField getEditorComponent() {
return editorComp;
}
@Override
public void removeItemAt(int index) {
E anObject = getItemAt(index);
super.removeItemAt(index);
editorComp.removePossibility(anObject.toString());
}
@Override
public E getItemAt(int index) {
return (E)super.getItemAt(index);
}
@Override
public E getSelectedItem() {
return (E)super.getSelectedItem();
}
}
/**
* A JTextField that will display a whole word as the user types a portion of
* it. A better example would be, as the user types the first letter in the
* word "text" the AutoCompleteTextField will display the letter "t" in the
* components current foreground color and display the rest of the word "ext"
* in the specified incomplete color (default is Color.GRAY.brighter()). The
* displayed text changes as the user types "e" so now getText() would return
* the string "te" and the incomplete portion displayed by the editor will be
* "xt." If Enter is pressed while an incomplete word is being processes, then
* the AutoCompleteTextField will replace what he user has typed with the
* completed word and consider itself "finished," and if Enter is pressed a
* second time, then it will fire a KeyEvent normally.
* @author Brandon Buck
* @version 1.0
*/
class AutoCompleteTextField extends JTextField implements KeyListener,
DocumentListener {
private ArrayList<String> possibilities;
private int currentGuess;
private Color incompleteColor;
private boolean areGuessing;
private boolean caseSensitive;
/**
* Constructs a new AutoCompleteTextField with the 5 columns by default and
* no case sensitivity on comparisons of guesses to entered text.
*/
public AutoCompleteTextField() {
this(5, false);
}
/**
* Constructs a new AutoCompleteTextField with the specified number of
* columns with no case sensitivity when comparing the current guess to the
* text entered.
* @param columns The number of columns you wish for the width of this AutoCompleteTextField.
*/
public AutoCompleteTextField(int columns) {
this(columns, false);
}
/**
* Creates a new AutoCompleteTextField with the given number of columns in
* width and the setting for case sensitivity when comparing the current
* guess to the entered text.
* @param columns The number of columns of text for this component.
* @param caseSensitive <code>true</code> or <code>false</code> depending on if you want comparisons to be case sensitive or not.
*/
public AutoCompleteTextField(int columns, boolean caseSensitive) {
super.setColumns(columns);
this.possibilities = new ArrayList<String>();
this.incompleteColor = Color.GRAY.brighter();
this.currentGuess = -1;
this.areGuessing = false;
this.caseSensitive = caseSensitive;
this.addKeyListener(this);
this.getDocument().addDocumentListener(this);
}
/** Add a new possibility to the list of possibilities.
* Add a new possibility to the list of possibilities for the
* AutoCommpleteTextField to process.
* @param possibility The new possibility to add.
*/
public void addPossibility(String possibility) {
this.possibilities.add(possibility);
Collections.sort(possibilities);
}
/** Removes a possibility from the list of possibilities.
* Removes the given possibility from the list of possibilities so that it
* will no longer be matched.
* @param possibility The possibility to remove.
*/
public void removePossibility(String possibility) {
this.possibilities.remove(possibility);
}
/** Removes all possibilities in the list.
* Removes every possibility in the list and starts over with an empty list
* ready for new possibilities to be added.
*/
public void removeAllPossibilities() {
this.possibilities = new ArrayList<String>();
}
/** Sets the color to draw the incomplete guess in.
* This sets the color that the incomplete guess text is drawn in.
* @param incompleteColor The new color to draw the incomplete guess with.
*/
public void setIncompleteColor(Color incompleteColor) {
this.incompleteColor = incompleteColor;
}
/** Returns the current guess from the list of possibilities.
* Returns the string at the location of the current guess in the list of
* possibilities.
* @return The current guess as a String.
*/
private String getCurrentGuess() {
if (this.currentGuess != -1)
return this.possibilities.get(this.currentGuess);
return this.getText();
}
/**
* Changes the current case sensitive setting to the given setting.
* @param caseSensitive <code>true</code> or <code>false</code> depending on if you want comparisons to be case sensitive or not.
*/
public void setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
private void findCurrentGuess() {
String entered = this.getText();
if (!this.caseSensitive)
entered = entered.toLowerCase();
for (int i = 0; i < this.possibilities.size(); i++) {
currentGuess = -1;
String possibility = this.possibilities.get(i);
if (!this.caseSensitive)
possibility = possibility.toLowerCase();
if (possibility.startsWith(entered)) {
this.currentGuess = i;
break;
}
}
}
@Override
public void setText(String text) {
super.setText(text);
this.areGuessing = false;
this.currentGuess = -1;
}
@Override
public void paintComponent(Graphics g) {
String guess = this.getCurrentGuess();
String drawGuess = guess;
super.paintComponent(g);
String entered = this.getText();
Rectangle2D enteredBounds = g.getFontMetrics().getStringBounds(entered, g);
if (!(this.caseSensitive)) {
entered = entered.toLowerCase();
guess = guess.toLowerCase();
}
if (!(guess.startsWith(entered)))
this.areGuessing = false;
if (entered != null && !(entered.equals(""))
&& this.areGuessing) {
String subGuess = drawGuess.substring(entered.length(), drawGuess.length());
Rectangle2D subGuessBounds = g.getFontMetrics().getStringBounds(drawGuess, g);
int centeredY = ((getHeight() / 2) + (int)(subGuessBounds.getHeight() / 2));
g.setColor(this.incompleteColor);
g.drawString(subGuess + " press ENTER to send or \u2192 to fill", (int)(enteredBounds.getWidth()) + 2, centeredY - 2);
}
}
public void keyTyped(KeyEvent e) { }
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (this.areGuessing) {
this.setText(this.getCurrentGuess());
this.areGuessing = false;
}
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
if (this.areGuessing) {
this.setText(this.getCurrentGuess());
this.areGuessing = false;
e.consume();
}
}
}
public void keyReleased(KeyEvent e) { }
public void insertUpdate(DocumentEvent e) {
String temp = this.getText();
if (temp.length() == 1)
this.areGuessing = true;
if (this.areGuessing)
this.findCurrentGuess();
}
public void removeUpdate(DocumentEvent e) {
String temp = this.getText();
if (!(this.areGuessing))
this.areGuessing = true;
if (temp.length() == 0)
this.areGuessing = false;
else if (this.areGuessing) {
this.findCurrentGuess();
}
}
public void changedUpdate(DocumentEvent e) { }
}
class AutoCompleteComboBoxEditor extends BasicComboBoxEditor {
public AutoCompleteComboBoxEditor() {
editor = createEditorComponent();
}
@Override
protected AutoCompleteTextField createEditorComponent() {
AutoCompleteTextField acEditor = new AutoCompleteTextField(9);
acEditor.setBorder(null);
return acEditor;
}
}
Related examples in the same category