Are you looking for customized advices? Click here to contact the expert!
by
2
7
7,366
1
Top 1% !
Popular
Famous
Pearl of Wisdom
Easy-to-find
Specified
OpenSource
Popularity: 736th place
Created
Modified Jul 2, 2014

Published on:

FrameworkSWT
JVMjre6
LanguageJava
LicenseMIT_X11

Java SWT: Combobox with AutoSuggestion feature

This component can be safely used when you want to have a combobox with the capability to display automatic filtered suggestions based on the text already entered.
It uses a couple of callback actions so that the caller can specify what to do when ENTER key is hit and how to load suggestions.
The call back actions are specified by a simple interface Callback with a single method.
Copy Embed Code
<iframe id="embedFrame" style="width:600px; height:300px;"
src="https://www.snip2code.com/Embed/81137/Java-SWT--Combobox-with-AutoSuggestion-f?startLine=0"></iframe>
Click on the embed code to copy it into your clipboard Width Height
Leave empty to retrieve all the content Start End
package com.snip2code.ui.swt; import java.util.List; import java.util.Random; import org.apache.log4j.Logger; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import com.snip2code.utils.Utils; /** * (c) 2011 snip2code inc. * This software is property of snip2code inc. Use or reproduction without permission is prohibited * * This widget creates a textfield with an autosuggestion feature. * The list of suggestion is shown when the user clicks on the text field or starts typing in the text field */ public class AutoSuggestionComposite extends Composite { protected static Logger log = Logger.getLogger(AutoSuggestionComposite.class); private Composite textBoxStackPanel; private StackLayout textboxLayout; private Text textBox; private Label tooltip; private Shell popupShell; private Table table; private String tooltipMsg; private ICallback<String, List<String>> loadSuggestionAction; private ICallback<String, String> onEnterAction; private String text; private int numOfDisplayedSuggestions; private static final String POPUPVISIB = "$$$POPUP_VISIB"; private String uniqueID; //used to differentiate AutoSuggestion composites in the same dialog private static Random rdn = new Random(); /** * Create the dialog. * @param parent * @param style * @param tooltipMsg message to display when no input is entered * @param numOfDisplayedSuggestions masimum number of items suggested in the popup of suggestions * @param loadSuggestionAction callback to routine that loads the suggestions for autocomplete * @param onEnterAction callback when enter is pressed on the textbox */ public AutoSuggestionComposite(Composite parent, int style, String tooltipMsg, int numOfDisplayedSuggestions, ICallback<String, List<String>> loadSuggestionAction, ICallback<String, String> onEnterAction) { super(parent, style); textboxLayout = new StackLayout(); this.loadSuggestionAction = loadSuggestionAction; this.onEnterAction = onEnterAction; this.numOfDisplayedSuggestions = numOfDisplayedSuggestions; this.tooltipMsg = tooltipMsg; uniqueID = rdn.nextInt() + tooltipMsg; createDialogArea(); } private void createDialogArea() { this.setBackground(SWTUIUtilities.WHITE); GridLayout gridLayout = new GridLayout(); gridLayout.marginHeight = 0; gridLayout.marginWidth = 0; this.setLayout(gridLayout); //Panel with textbox and tooltip: textBoxStackPanel = new Composite(this, SWT.NONE); textBoxStackPanel.setLayout(textboxLayout); GridData gdPanel = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1); gdPanel.verticalIndent = 2; textBoxStackPanel.setLayoutData(gdPanel); tooltip = new Label(textBoxStackPanel, SWT.NONE); tooltip.setBackground(SWTUIUtilities.WHITE); tooltip.setForeground(SWTUIUtilities.LIGHT_GREY); tooltip.setFont(SWTUIUtilities.LBL_TEXT); tooltip.setText(" " + tooltipMsg); //manual horizontal indent, cause StackLayout doesn't allow this feature tooltip.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { setControlVisib(textBox, true); textBoxStackPanel.layout(); textBox.setFocus(); loadSuggestions(null); } }); textBox = new Text(textBoxStackPanel, SWT.NONE); textBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); textBox.setFont(SWTUIUtilities.LBL_TEXT); textBox.setBackground(SWTUIUtilities.WHITE); textBox.setData(POPUPVISIB, uniqueID); //popup for suggestions: popupShell = new Shell(getShell().getDisplay(), SWT.ON_TOP); popupShell.setLayout(new FillLayout()); popupShell.setData(POPUPVISIB, uniqueID); popupShell.setBackground(SWTUIUtilities.WHITE); table = new Table(popupShell, SWT.SINGLE); table.getVerticalBar().setVisible(false); table.setFont(SWTUIUtilities.LBL_TEXT); table.setData(POPUPVISIB, uniqueID); for (int i = 0; i < numOfDisplayedSuggestions; i++) { new TableItem(table, SWT.NONE); } //Key Listener for Keyboards events: textBox.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { boolean loadSuggestions = true; saveInput(); switch (e.keyCode) { case SWT.ARROW_DOWN: int index = (table.getSelectionIndex() + 1) % table.getItemCount(); table.setSelection(index); e.doit = false; break; case SWT.ARROW_UP: index = table.getSelectionIndex() - 1; if (index < 0) index = table.getItemCount() - 1; table.setSelection(index); e.doit = false; break; case SWT.CR: case SWT.LF: case 16777296: //enter in numeric keypad if (popupShell.isVisible() && table.getSelectionIndex() != -1) { textBox.setText(table.getSelection()[0].getText()); } loadSuggestions = false; execEnterAction(); break; case SWT.ESC: popupShell.setVisible(false); break; } //only for printable characters, load search history: if (loadSuggestions && (e.keyCode < 256)) loadSuggestions(textBox.getText()); log.debug("End of key listener"); } }); //make sure the input entered in the text box is saved and ready to use: textBox.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { log.debug("Focus lost by textbox of autosugg from " + tooltipMsg); saveInput(); checkTooltipVisib(); handleFocusLost(); } @Override public void focusGained(FocusEvent e) { if (isDisposed() || getShell().isDisposed() || getShell().getDisplay().isDisposed()) return; log.debug("Focus gained by textbox of autosugg from " + tooltipMsg); loadSuggestions(textBox.getText()); } }); textBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { checkTooltipVisib(); } }); table.addListener(SWT.DefaultSelection, new Listener() { public void handleEvent(Event event) { textBox.setText(table.getSelection()[0].getText()); execEnterAction(); } }); //hide the popup of suggestions if the focus is out: Listener focusOutListener = new Listener() { public void handleEvent(Event event) { handleFocusLost(); } }; table.addListener(SWT.FocusOut, focusOutListener); textBox.addListener(SWT.FocusOut, focusOutListener); textBoxStackPanel.addListener(SWT.FocusOut, focusOutListener); popupShell.addListener(SWT.FocusOut, focusOutListener); this.addListener(SWT.FocusOut, focusOutListener); getShell().addListener(SWT.Move, new Listener() { public void handleEvent(Event event) { popupShell.setVisible(false); checkTooltipVisib(); } }); checkTooltipVisib(); } private void handleFocusLost() { /* async is needed to wait until focus reaches its new Control */ if (isDisposed() || getShell().isDisposed() || getShell().getDisplay().isDisposed()) return; getShell().getDisplay().asyncExec(new Runnable() { public void run() { log.debug("Running handleFocusLost for " + tooltipMsg); if (isDisposed() || getShell().isDisposed() || getShell().getDisplay().isDisposed()) return; Control control = getShell().getDisplay().getFocusControl(); log.debug("handleFocusLost for " + tooltipMsg + ": control is " + control + ";uniqueID:" + uniqueID); if ((control == null) || (control.getData(POPUPVISIB) == null) || !control.getData(POPUPVISIB).toString().equals(uniqueID)) { popupShell.setVisible(false); } } }); } /** * Determines the visibility of textbox content vs tooltip when the textbox is empty */ public void checkTooltipVisib() { if (Utils.isNullOrEmpty(textBox.getText())) setControlVisib(tooltip, true); else setControlVisib(textBox, true); textBoxStackPanel.layout(); } private void execEnterAction() { saveInput(); popupShell.setVisible(false); onEnterAction.exec(text); } private void loadSuggestions(String prefix) { log.debug("loading suggestions for " + prefix); // if (Utils.isNullOrEmpty(prefix)) // return; Rectangle textBounds = getShell().getDisplay().map(textBoxStackPanel, null, textBox.getBounds()); //load suggestions: List<String> suggestions = loadSuggestionAction.exec(prefix); log.debug("loaded " + suggestions.size() + " suggestions"); table.setItemCount(suggestions.size()); TableItem[] items = table.getItems(); int maxWidthOfItem = 0; log.debug("Changing " + items.length + " items in TablePopup"); for (int i = 0; i < items.length; i++) { if (i < suggestions.size()) { String sugg = suggestions.get(i); if (!Utils.isNullOrEmpty(sugg)) { items[i].setText(sugg); int w = items[i].getBounds().width; if (w > maxWidthOfItem) maxWidthOfItem = w; } } } // //avoid the display of horizontal scrollbar when not needed (10 is the width of the scrollbar) // if ((maxWidthOfItem + 10) < textBounds.width) // table.pack(); //23 pixels is the height of 1 item in the drop down list; //always add a blank line at the end of the list to improve readability int popupHeight = (suggestions.size() + 1) * 23; log.debug("popupHeight for [" + this.tooltipMsg + "]:" + popupHeight); if (popupHeight <= 46) popupHeight = 46; //set a cap to the maximum height of the popup (17 lines): if (popupHeight > 391) { popupHeight = 391; table.getVerticalBar().setVisible(true); } else { //avoid the display of horizontal scrollbar when not needed (10 is the width of the scrollbar) if ((maxWidthOfItem + 10) < textBounds.width) table.pack(); table.getVerticalBar().setVisible(false); } log.debug("setBounds popup:" + textBounds.x + ";" + (textBounds.y + textBounds.height + 4) + ";" + textBounds.width + ";" + popupHeight); popupShell.setBounds(textBounds.x, textBounds.y + textBounds.height + 4, textBounds.width, popupHeight); popupShell.setVisible(true); } private void setControlVisib(Control c, boolean visible) { if (c == null) return; if (visible) textboxLayout.topControl = c; } private void saveInput() { text = textBox.getText(); if (text == null) text = ""; text = text.trim(); } /** * Returns the content of the textbox */ public String getText() { return text; } /** * Sets the content of the textbox */ public void setText(String text) { this.text = text; textBox.setText(text); setControlVisib(textBox, true); } /** * Hides the popup of suggestions */ public void hideSuggestions() { popupShell.setVisible(false); } @Override public void dispose() { if (popupShell != null) { hideSuggestions(); popupShell.dispose(); } super.dispose(); } }
If you want to be updated about similar snippets, Sign in and follow our Channels

blog comments powered by Disqus