Filternde Combobox in JTable verliert Fokus nach erster Eingabe

nieselfriem

Bekanntes Mitglied
Hallo!

Ich habe unten stehende JComboBox Implementierung in eine Tabellenzelle eingefügt. Klappt auch so weit ganz gut. Leier verliert schon bei der ersten Eingabe die Zelle den Fokus, so dass mein die Eingabe nicht fortsetzen kann. So wird immer nur der erste Eintrag ausgewählt. Wenn z.B. Die Einträge Maler und Maurer in der Liste sind, so wird bei der Eingabe des Buchstabens M sofort der Maler ausgewählt und nicht die Eingabe bis zum dritten Buchstaben abgewartet. Wie kann ich es bewerkstelligen, dass der Fokus auch nach der ersten und weiteren Eingabe eines Buchstabens erhalten bleibt.
Java:
package guitests;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * Eine editierbare Combobox, die den nächsten wahrscheinlichen
 * Eintrag vorschlägt. 
 * @author  Aljoscha Rittner
 * @version 1.0 (immer noch ;-)
 */
public class JSelComboBox extends JComboBox implements KeyListener {

  // Nur Einträge der Liste editierbar
  boolean inputListItemsOnly = true;
  boolean caseSensitive      = false;

  public JSelComboBox () {
    super();
    setEditable(true);
    getEditor().getEditorComponent().addKeyListener(this);
  }

  public JSelComboBox (Object[] items) {
    super(items);
    setEditable(true);
    getEditor().getEditorComponent().addKeyListener(this);
  }

  /**
   * Setzt das Verhalten für Eingaben, die nicht den Listeneinträgen
   * entsprechen.
   * @param bOnly true: nur Listeinträge; false: alle Eingaben
   *              erlauben.
   */
  public void setInputListItemsOnly (boolean bOnly) {
    inputListItemsOnly = bOnly;
  }

  /**
   * Gibt das Verhalten für Eingaben, die nicht den Listeneinträgen
   * entsprechen zurück.
   * @return true: nur Listeinträge; false: alle Eingaben erlauben
   */
  public boolean isInputListItemsOnly () {
    return inputListItemsOnly;
  }

  /**
   * Setzt das Verhalten für die Suche der Listeneinträge.
   * @param bCaseSensitive true: Groß/Kleinschreibung ist notwendig
   */
  public void setCaseSensitive (boolean bCaseSensitive) {
    caseSensitive = bCaseSensitive;
  }

  /**
   * Gibt das Verhalten für die Suche der Listeneinträge zurück.
   * @param bCaseSensitive true: Groß/Kleinschreibung ist notwendig
   */
  public boolean isCaseSensitive () {
    return caseSensitive;
  }

  public void keyReleased(final java.awt.event.KeyEvent p1) {
       if (! isPopupVisible() ) {
      setPopupVisible(true);
    }
  }

  public void keyPressed(final java.awt.event.KeyEvent p1) {
    if (! isPopupVisible() ) {
      setPopupVisible(true);
    }
    if (p1.getKeyCode() == p1.VK_DELETE) {
      JTextField jtf = (JTextField) getEditor().getEditorComponent();
      resetInput();
      p1.consume();
    }
  }

  public void keyTyped(final java.awt.event.KeyEvent p1) {
    int nPos = -1;
    String search = null;

    JTextField jtf = (JTextField) getEditor().getEditorComponent();

    nPos = jtf.getSelectionStart();
    if ( nPos != -1 ) {
      if ( p1.getKeyChar() == p1.VK_BACK_SPACE ) {
        search = jtf.getText()
          .substring(0, nPos == 0 ? nPos : nPos-1);
        if ( search.equals("") ) {
          resetInput();
          p1.consume();
          return;
        }
      } else {
        search = jtf.getText().substring(0, nPos);
        search = search + p1.getKeyChar();
      }

      findAndSel (search, p1);
    } else {
      setSelectedIndex(-1);
    }
  }

  /**
   * Sucht einen Eintrag anhand einer Zeichenkette und wählt evtl.
   * eine Zeile aus.
   * Wenn nur Listeneinträge ausgewählt werden dürfen und die
   * Zeichenkette nicht gefunden wurde, dann wird die Eingabe
   * verhindert.
   * @param search Zeichenkette für die Suche
   * @param p1     Event des Tastendruckes
   */
  protected void findAndSel (String search,
                             java.awt.event.KeyEvent p1) {
    JTextField jtf = (JTextField) getEditor().getEditorComponent();
    int start = getSelectedIndex() + 1;
    int index = findString (search, start);

    if ( index == -1 )
      index = findString (search, start-1);

    if ( index == -1 )
      index = findString (search, 0);

    if ( index != -1 ) {
      System.out.println(index);
      String found = getModel().getElementAt(index).toString();
      setSelectedIndex(index);
      jtf.setText(found);
      jtf.setCaretPosition (search.length());
      jtf.setSelectionEnd (found.length());
      jtf.setSelectionStart (search.length());
      p1.consume();
    } else {
      if ( isInputListItemsOnly () ) {
        getToolkit().beep();
        p1.consume();
      }
    }
  }

  /**
   * Sucht einen Eintrag anhand einer Zeichenkette und gibt die Zeile
   * zurück.
   */
  protected int findString (String search, int start) {
    ComboBoxModel cbm = getModel();
    if ( start < 0 ) start = 0;
    for ( int i = start; i < cbm.getSize(); i++ ) {
      if (isCaseSensitive()) {
        if ( cbm.getElementAt(i).toString().startsWith(search) ) {
          return i;
        }
      } else {
        if ( cbm.getElementAt(i).toString().toLowerCase()
             .startsWith(search.toLowerCase()) ) {
          return i;
        }
      }
    }
    return -1;
  }

  /**
   * Setzt die Eingaben und die Auswahlzeile zurück.
   */
  protected void resetInput() {
    JTextField jtf = (JTextField) getEditor().getEditorComponent();
    if ( isInputListItemsOnly () == false ) {
      jtf.setText("");
      jtf.setCaretPosition(0);
      setSelectedIndex(-1);
    } else {
      jtf.setText (getModel().getElementAt(0).toString());
      setSelectedIndex(0);
      jtf.setSelectionEnd(jtf.getText().length());
      jtf.setSelectionStart(0);
    }
  }
}
erstellen der Combobox
Java:
 public JSelComboBox berufBerufDrop() {
        Vector berufe = new Vector();
        berufe.add("Eletriker");
        berufe.add("Fließenleger");
        berufe.add("Koch");
        berufe.add("Maler");
        berufe.add("Maurer");
        berufe.add("Tischler");
        JSelComboBox berBeruf = new JSelComboBox();
        DefaultComboBoxModel model = new DefaultComboBoxModel(berufe);
        berBeruf.setModel(model);
        berBeruf.setMaximumRowCount(4);
        return berBeruf;
    }
Einfügen in die Tabelle
Java:
        jBerufeTBL.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(tblComponents.berufBerufDrop()));

Gruß niesel
 
Wenn z.B. Die Einträge Maler und Maurer in der Liste sind, so wird bei der Eingabe des Buchstabens M sofort der Maler ausgewählt und nicht die Eingabe bis zum dritten Buchstaben abgewartet. Wie kann ich es bewerkstelligen, dass der Fokus auch nach der ersten und weiteren Eingabe eines Buchstabens erhalten bleibt.
In dem Du nicht setSelectedIndex(...) aufrufst ;-)

Keine Ahnung, ob es dafür eine einfach Lösung gibt. Standardmäßig kann man durch Drücken eines Buchstabens durch die Einträge navigieren, die mit diesem Buchstaben anfangen. Eventuell kann man sich da im Quellcode was abschauen. Vielleicht ist es sogar einfacher sich sowas selbst zu bauen mittels JTextField und einer JList in einem JPopupMenu
 
Wenn ich aber diese Klasse in einer JComboBox aufrufe die nicht in einer Tabellenzelle integriert ist, kann ich die Eingaben fortsetzen.
Gibt es da einen Kniff?

Gruß niesel
 

Zurück
Oben