AutoComplete SwingX

Estava pesquisando sobre autocomplete e achei esse exemplo da propria SWINGX

http://swinglabs.java.sun.com/hudson/job/Swinglabs%20Demos%20Continuous%20Build/ws/swingx.jnlp

Conforme o exemplo gostaria de saber como fazer(Procurei pelo codigo e naum achei, naum entendi os Docs):

  • JComboBox( NON-STRICT)
  • JComboBox w/Multiple String

Valeus

O que são essas coisas?

o exemplo ta no link,

Primeiro você faz uma JComboBox normal. Se ela for Strict, você marca ela como “setEditable(false)”. Se ela não for strict, vc não faz isso.

Depois, você usa o AutoCompleteDecorator na sua ComboBox. E pronto!

Se vc quiser, pode usar essa classe que facilita esse processo:

[code]import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Collection;
import java.util.Vector;

import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.UIManager;
import javax.swing.text.JTextComponent;

public class AutoCompleteComboBox extends JComboBox
{
public AutoCompleteComboBox()
{
super();
initialize(false);
}

public AutoCompleteComboBox(ComboBoxModel aModel)
{
    super(aModel);
    initialize(false);
}

public AutoCompleteComboBox(Object... items)
{
    super(items);
    initialize(false);
}

public AutoCompleteComboBox(Collection< ? > items)
{
    super(new Vector<Object>(items));
    initialize(false);
}

public AutoCompleteComboBox(boolean editable)
{
    super();
    initialize(editable);
}

public AutoCompleteComboBox(ComboBoxModel aModel, boolean editable)
{
    super(aModel);
    initialize(editable);
}

public AutoCompleteComboBox(Collection< ? > items, boolean editable)
{
    super(new Vector<Object>(items));
    initialize(editable);
}

private void initialize(boolean editable)
{
    setEditable(editable);

    AutoCompleteDecorator.decorate(this);
    final Color gray = getBackground();
    final Color green = UIManager.getColor("ComboBox.selectionBackground");
    // final Color selection = ((JTextComponent)
    // getEditor().getEditorComponent()).getSelectionColor();

    getEditor().getEditorComponent().setBackground(gray);
    ((JTextComponent) getEditor().getEditorComponent()).setSelectionColor(gray);
    ((JTextComponent) getEditor().getEditorComponent()).setCaretColor(Color.white);
    ((JTextComponent) getEditor().getEditorComponent()).setForeground(((JTextComponent) getEditor().getEditorComponent()).getSelectedTextColor());

    getEditor().getEditorComponent().addFocusListener(new FocusListener()
    {
        public void focusGained(FocusEvent e)
        {
            getEditor().getEditorComponent().setBackground(green);
            ((JTextComponent) getEditor().getEditorComponent()).setSelectionColor(green);
        }

        public void focusLost(FocusEvent e)
        {
            getEditor().getEditorComponent().setBackground(gray);
            ((JTextComponent) getEditor().getEditorComponent()).setSelectionColor(gray);
        }
    });
}

@Override
public void setEnabled(boolean b)
{
    super.setEnabled(b);
    getEditor().getEditorComponent().setBackground(getBackground());
}

}[/code]

Nós também fizemos algumas correções no Decorator do SwingX:

[code]import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ComboBoxEditor;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;

import org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor;
import org.jdesktop.swingx.autocomplete.AutoCompleteComboBoxEditor;
import org.jdesktop.swingx.autocomplete.AutoCompleteDocument;
import org.jdesktop.swingx.autocomplete.ComboBoxAdaptor;
import org.jdesktop.swingx.autocomplete.ObjectToStringConverter;
import org.jdesktop.swingx.autocomplete.workarounds.AquaLnFPopupLocationFix;

/**

  • This class contains only static utility methods that can be used to set up

  • automatic completion for some Swing components.

  • Usage examples:

  • <pre><code>

  • JComboBox comboBox = […];

  • AutoCompleteDecorator.<b>decorate</b>(comboBox);

  • List items = […];

  • JTextField textField = […];

  • AutoCompleteDecorator.<b>decorate</b>(textField, items);

  • JList list = […];

  • JTextField textField = […];

  • AutoCompleteDecorator.<b>decorate</b>(list, textField);

  • </code></pre>

  • @author Thomas Bierhance
    */
    public class AutoCompleteDecorator
    {

    /**

    • Enables automatic completion for the given JComboBox. The automatic
    • completion will be strict (only items from the combo box can be selected)
    • if the combo box is not editable.
    • @param comboBox a combo box
      */
      public static void decorate(final JComboBox comboBox)
      {
      decorate(comboBox, ObjectToStringConverter.DEFAULT_IMPLEMENTATION);
      }

    /**

    • Enables automatic completion for the given JComboBox. The automatic

    • completion will be strict (only items from the combo box can be selected)

    • if the combo box is not editable.

    • @param comboBox a combo box

    • @param stringConverter the converter used to transform items to strings
      */
      public static void decorate(final JComboBox comboBox,
      final ObjectToStringConverter stringConverter)
      {
      boolean strictMatching = !comboBox.isEditable();
      // has to be editable
      comboBox.setEditable(true);
      // fix the popup location
      AquaLnFPopupLocationFix.install(comboBox);

      // configure the text component=editor component
      JTextComponent editorComponent = (JTextComponent) comboBox.getEditor().getEditorComponent();
      final AbstractAutoCompleteAdaptor adaptor = new ComboBoxAdaptor(
      comboBox);
      final AutoCompleteDocument document = new AutoCompleteDocument(adaptor,
      strictMatching, stringConverter);
      decorate(editorComponent, document, adaptor);

      // show the popup list when the user presses a key
      final KeyListener keyListener = new KeyAdapter()
      {
      @Override
      public void keyPressed(KeyEvent keyEvent)
      {
      // don’t popup on action keys (cursor movements, etc…)
      if (keyEvent.isActionKey())
      return;
      // don’t popup if the combobox isn’t visible anyway
      if (comboBox.isDisplayable() && !comboBox.isPopupVisible())
      {
      int keyCode = keyEvent.getKeyCode();
      // don’t popup when the user hits shift,ctrl or alt
      if (keyCode == KeyEvent.VK_SHIFT
      || keyCode == KeyEvent.VK_CONTROL
      || keyCode == KeyEvent.VK_ALT)
      return;
      // don’t popup when the user hits escape (see issue #311)
      if (keyCode == KeyEvent.VK_ESCAPE
      || keyCode == KeyEvent.VK_ENTER)
      return;

               if (keyEvent.isAltDown() || keyEvent.isControlDown())
                   return;
      
               comboBox.setPopupVisible(true);
           }
       }
      

      };
      editorComponent.addKeyListener(keyListener);

      if (stringConverter != ObjectToStringConverter.DEFAULT_IMPLEMENTATION)
      {
      comboBox.setEditor(new AutoCompleteComboBoxEditor(
      comboBox.getEditor(), stringConverter));
      }

      // Changing the l&f can change the combobox’ editor which in turn
      // would not be autocompletion-enabled. The new editor needs to be
      // set-up.
      comboBox.addPropertyChangeListener(“editor”,
      new PropertyChangeListener()
      {
      public void propertyChange(PropertyChangeEvent e)
      {
      ComboBoxEditor editor = (ComboBoxEditor) e.getNewValue();
      if (editor != null
      && editor.getEditorComponent() != null)
      {
      if (!(editor instanceof AutoCompleteComboBoxEditor)
      && stringConverter != ObjectToStringConverter.DEFAULT_IMPLEMENTATION)
      {
      comboBox.setEditor(new AutoCompleteComboBoxEditor(
      editor, stringConverter));
      // Don’t do the decorate step here because
      // calling setEditor will trigger
      // the propertychange listener a second time,
      // which will do the decorate
      // and addKeyListener step.
      }
      else
      {
      decorate(
      (JTextComponent) editor.getEditorComponent(),
      document, adaptor);
      editor.getEditorComponent().addKeyListener(
      keyListener);
      }
      }
      }
      });
      }

    /**

    • Decorates a given text component for automatic completion using the given

    • AutoCompleteDocument and AbstractAutoCompleteAdaptor.

    • @param textComponent a text component that should be decorated

    • @param document the AutoCompleteDocument to be installed on the text

    •    component
      
    • @param adaptor the AbstractAutoCompleteAdaptor to be used
      */
      public static void decorate(JTextComponent textComponent,
      AutoCompleteDocument document,
      final AbstractAutoCompleteAdaptor adaptor)
      {
      // install the document on the text component
      textComponent.setDocument(document);

      // mark entire text when the text component gains focus
      // otherwise the last mark would have been retained which is quiet
      // confusing
      textComponent.addFocusListener(new FocusAdapter()
      {
      @Override
      public void focusGained(FocusEvent e)
      {
      adaptor.markEntireText();
      }
      });

      // Tweak some key bindings
      InputMap editorInputMap = textComponent.getInputMap();
      if (document.isStrictMatching())
      {
      // move the selection to the left on VK_BACK_SPACE
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_BACK_SPACE, 0),
      DefaultEditorKit.selectionBackwardAction);
      // ignore VK_DELETE and CTRL+VK_X and beep instead when strict
      // matching
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_DELETE, 0), errorFeedbackAction);
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_X,
      java.awt.event.InputEvent.CTRL_DOWN_MASK),
      errorFeedbackAction);
      }
      else
      {
      ActionMap editorActionMap = textComponent.getActionMap();
      // leave VK_DELETE and CTRL+VK_X as is
      // VK_BACKSPACE will move the selection to the left if the selected
      // item is in the list
      // it will delete the previous character otherwise
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_BACK_SPACE, 0),
      “nonstrict-backspace”);
      editorActionMap.put(
      “nonstrict-backspace”,
      new NonStrictBackspaceAction(
      editorActionMap.get(DefaultEditorKit.deletePrevCharAction),
      editorActionMap.get(DefaultEditorKit.selectionBackwardAction),
      adaptor));
      }
      }

    static class NonStrictBackspaceAction extends TextAction
    {
    Action backspace;
    Action selectionBackward;
    AbstractAutoCompleteAdaptor adaptor;

     public NonStrictBackspaceAction(Action backspace,
             Action selectionBackward, AbstractAutoCompleteAdaptor adaptor)
     {
         super("nonstrict-backspace");
         this.backspace = backspace;
         this.selectionBackward = selectionBackward;
         this.adaptor = adaptor;
     }
    
     public void actionPerformed(ActionEvent e)
     {
         if (adaptor.listContainsSelectedItem())
         {
             selectionBackward.actionPerformed(e);
         }
         else
         {
             backspace.actionPerformed(e);
         }
     }
    

    }

    /**

    • A TextAction that provides an error feedback for the text component that
    • invoked the action. The error feedback is most likely a “beep”.
      */
      static Object errorFeedbackAction = new TextAction(“provide-error-feedback”)
      {
      public void actionPerformed(ActionEvent e)
      {
      UIManager.getLookAndFeel().provideErrorFeedback(getTextComponent(e));
      }
      };
      }[/code]

Quais correções?

Fizemos uns ajustes para ele trabalhar bem na JTable. Ele tinha uns problemas ao se pressionar ESC ou quando vc clicava no scroll enquanto o editor estava selecionado.

Mas agora nem estamos usando mais esse componente. Fizemos um novo combobox que, além do autocompletion, filtra também o seu interior. Tem até suporte a wildcards como *Product.

ViniGodoy,

Por acaso você não pode disponibilizar a parte do Filter do seu código?
Implementei um JComboBox com uma JTable como CellRenderer e estou tentando aplicar um filtro nos resultados disparando através do keyReleased do ComboEditor.
Porém, não estou conseguindo chegar a um resultado.

Obrigado.

[quote=ViniGodoy]Fizemos uns ajustes para ele trabalhar bem na JTable. Ele tinha uns problemas ao se pressionar ESC ou quando vc clicava no scroll enquanto o editor estava selecionado.

Mas agora nem estamos usando mais esse componente. Fizemos um novo combobox que, além do autocompletion, filtra também o seu interior. Tem até suporte a wildcards como *Product.
[/quote]

Não dispare eventos através do comboeditor. O comboeditor é um JTextField, logo tem um Document associado. Você deve alterar esse Document. Vou ver se ajeito o código e posto aqui.

Olá VinyGodoy

Não querendo ressucitar o tópico, mas,

Tive problemas ao utilizar este classe

em

import org.jdesktop.swingx.autocomplete.workarounds.AquaLnFPopupLocationFix;

Atualizei minha versao do SwingX e nada.

Poderia me ajudar.

Grato

hum, essa nunca usei, mas o nome do pacote ali não é dos melhores…

[quote=ViniGodoy]Nós também fizemos algumas correções no Decorator do SwingX:

[code]import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ComboBoxEditor;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;

import org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor;
import org.jdesktop.swingx.autocomplete.AutoCompleteComboBoxEditor;
import org.jdesktop.swingx.autocomplete.AutoCompleteDocument;
import org.jdesktop.swingx.autocomplete.ComboBoxAdaptor;
import org.jdesktop.swingx.autocomplete.ObjectToStringConverter;
import org.jdesktop.swingx.autocomplete.workarounds.AquaLnFPopupLocationFix;

/**

  • This class contains only static utility methods that can be used to set up

  • automatic completion for some Swing components.

  • Usage examples:

  • <pre><code>

  • JComboBox comboBox = […];

  • AutoCompleteDecorator.<b>decorate</b>(comboBox);

  • List items = […];

  • JTextField textField = […];

  • AutoCompleteDecorator.<b>decorate</b>(textField, items);

  • JList list = […];

  • JTextField textField = […];

  • AutoCompleteDecorator.<b>decorate</b>(list, textField);

  • </code></pre>

  • @author Thomas Bierhance
    */
    public class AutoCompleteDecorator
    {

    /**

    • Enables automatic completion for the given JComboBox. The automatic
    • completion will be strict (only items from the combo box can be selected)
    • if the combo box is not editable.
    • @param comboBox a combo box
      */
      public static void decorate(final JComboBox comboBox)
      {
      decorate(comboBox, ObjectToStringConverter.DEFAULT_IMPLEMENTATION);
      }

    /**

    • Enables automatic completion for the given JComboBox. The automatic

    • completion will be strict (only items from the combo box can be selected)

    • if the combo box is not editable.

    • @param comboBox a combo box

    • @param stringConverter the converter used to transform items to strings
      */
      public static void decorate(final JComboBox comboBox,
      final ObjectToStringConverter stringConverter)
      {
      boolean strictMatching = !comboBox.isEditable();
      // has to be editable
      comboBox.setEditable(true);
      // fix the popup location
      AquaLnFPopupLocationFix.install(comboBox);

      // configure the text component=editor component
      JTextComponent editorComponent = (JTextComponent) comboBox.getEditor().getEditorComponent();
      final AbstractAutoCompleteAdaptor adaptor = new ComboBoxAdaptor(
      comboBox);
      final AutoCompleteDocument document = new AutoCompleteDocument(adaptor,
      strictMatching, stringConverter);
      decorate(editorComponent, document, adaptor);

      // show the popup list when the user presses a key
      final KeyListener keyListener = new KeyAdapter()
      {
      @Override
      public void keyPressed(KeyEvent keyEvent)
      {
      // don’t popup on action keys (cursor movements, etc…)
      if (keyEvent.isActionKey())
      return;
      // don’t popup if the combobox isn’t visible anyway
      if (comboBox.isDisplayable() && !comboBox.isPopupVisible())
      {
      int keyCode = keyEvent.getKeyCode();
      // don’t popup when the user hits shift,ctrl or alt
      if (keyCode == KeyEvent.VK_SHIFT
      || keyCode == KeyEvent.VK_CONTROL
      || keyCode == KeyEvent.VK_ALT)
      return;
      // don’t popup when the user hits escape (see issue #311)
      if (keyCode == KeyEvent.VK_ESCAPE
      || keyCode == KeyEvent.VK_ENTER)
      return;

               if (keyEvent.isAltDown() || keyEvent.isControlDown())
                   return;
      
               comboBox.setPopupVisible(true);
           }
       }
      

      };
      editorComponent.addKeyListener(keyListener);

      if (stringConverter != ObjectToStringConverter.DEFAULT_IMPLEMENTATION)
      {
      comboBox.setEditor(new AutoCompleteComboBoxEditor(
      comboBox.getEditor(), stringConverter));
      }

      // Changing the l&f can change the combobox’ editor which in turn
      // would not be autocompletion-enabled. The new editor needs to be
      // set-up.
      comboBox.addPropertyChangeListener(“editor”,
      new PropertyChangeListener()
      {
      public void propertyChange(PropertyChangeEvent e)
      {
      ComboBoxEditor editor = (ComboBoxEditor) e.getNewValue();
      if (editor != null
      && editor.getEditorComponent() != null)
      {
      if (!(editor instanceof AutoCompleteComboBoxEditor)
      && stringConverter != ObjectToStringConverter.DEFAULT_IMPLEMENTATION)
      {
      comboBox.setEditor(new AutoCompleteComboBoxEditor(
      editor, stringConverter));
      // Don’t do the decorate step here because
      // calling setEditor will trigger
      // the propertychange listener a second time,
      // which will do the decorate
      // and addKeyListener step.
      }
      else
      {
      decorate(
      (JTextComponent) editor.getEditorComponent(),
      document, adaptor);
      editor.getEditorComponent().addKeyListener(
      keyListener);
      }
      }
      }
      });
      }

    /**

    • Decorates a given text component for automatic completion using the given

    • AutoCompleteDocument and AbstractAutoCompleteAdaptor.

    • @param textComponent a text component that should be decorated

    • @param document the AutoCompleteDocument to be installed on the text

    •    component
      
    • @param adaptor the AbstractAutoCompleteAdaptor to be used
      */
      public static void decorate(JTextComponent textComponent,
      AutoCompleteDocument document,
      final AbstractAutoCompleteAdaptor adaptor)
      {
      // install the document on the text component
      textComponent.setDocument(document);

      // mark entire text when the text component gains focus
      // otherwise the last mark would have been retained which is quiet
      // confusing
      textComponent.addFocusListener(new FocusAdapter()
      {
      @Override
      public void focusGained(FocusEvent e)
      {
      adaptor.markEntireText();
      }
      });

      // Tweak some key bindings
      InputMap editorInputMap = textComponent.getInputMap();
      if (document.isStrictMatching())
      {
      // move the selection to the left on VK_BACK_SPACE
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_BACK_SPACE, 0),
      DefaultEditorKit.selectionBackwardAction);
      // ignore VK_DELETE and CTRL+VK_X and beep instead when strict
      // matching
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_DELETE, 0), errorFeedbackAction);
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_X,
      java.awt.event.InputEvent.CTRL_DOWN_MASK),
      errorFeedbackAction);
      }
      else
      {
      ActionMap editorActionMap = textComponent.getActionMap();
      // leave VK_DELETE and CTRL+VK_X as is
      // VK_BACKSPACE will move the selection to the left if the selected
      // item is in the list
      // it will delete the previous character otherwise
      editorInputMap.put(KeyStroke.getKeyStroke(
      java.awt.event.KeyEvent.VK_BACK_SPACE, 0),
      “nonstrict-backspace”);
      editorActionMap.put(
      “nonstrict-backspace”,
      new NonStrictBackspaceAction(
      editorActionMap.get(DefaultEditorKit.deletePrevCharAction),
      editorActionMap.get(DefaultEditorKit.selectionBackwardAction),
      adaptor));
      }
      }

    static class NonStrictBackspaceAction extends TextAction
    {
    Action backspace;
    Action selectionBackward;
    AbstractAutoCompleteAdaptor adaptor;

     public NonStrictBackspaceAction(Action backspace,
             Action selectionBackward, AbstractAutoCompleteAdaptor adaptor)
     {
         super("nonstrict-backspace");
         this.backspace = backspace;
         this.selectionBackward = selectionBackward;
         this.adaptor = adaptor;
     }
    
     public void actionPerformed(ActionEvent e)
     {
         if (adaptor.listContainsSelectedItem())
         {
             selectionBackward.actionPerformed(e);
         }
         else
         {
             backspace.actionPerformed(e);
         }
     }
    

    }

    /**

    • A TextAction that provides an error feedback for the text component that
    • invoked the action. The error feedback is most likely a “beep”.
      */
      static Object errorFeedbackAction = new TextAction(“provide-error-feedback”)
      {
      public void actionPerformed(ActionEvent e)
      {
      UIManager.getLookAndFeel().provideErrorFeedback(getTextComponent(e));
      }
      };
      }[/code][/quote]

Irmao… onde da pra pegar os jar’s usados nessa classe

to querendo usa-la mas n acho!!

https://swingx.dev.java.net/servlets/ProjectDocumentList?folderID=12289&expandFolder=12289&folderID=0

cara consegui implementar sua classe, mas me responde uma pergunta ele não filtra os dados da jComboBox sendo q os dados vem do banco?

att,

Devia filtrar qualquer coisa.

Mesmo puxando os dados do banco?

pq qnd vou digitar ele não filtra mostra todos os dados q tem na tabela sem fazer o filtro e permanece assim ate terminar de digitar…

Ele filtra o conteúdo que estiver no combo. Não interessa se você carregou do banco, ou de qualquer outro lugar.

Eh entao acho q estou fazendo algo muito errado…

qnd vc implemento ele o combo ficava em branco e na medida que ia digitar ele ia dando as opção que tem com as letras ja digitadas n era isso?

Isso… e é isso que é auto-complete. Você quer dar opções que não estão na combo? O que você quer exatamente?