JTextField & JPopupMenu

Hallo Pete,

hab im Konstruktor der JList einen MouseListener hinzugefügt. Bei einfachem Klick wird das entsprechende Wort in das Textfeld eingefügt, das Popup bleibt jedoch offen. Durch Doppelklick wird sowohl das selektierte Wort eingefügt als auch das Popup geschlossen.

Java:
import java.awt.event.*;

import javax.swing.*;
import javax.swing.text.DefaultCaret;
import javax.swing.text.Position;

public class TextFieldExtended extends JFrame implements KeyListener {

	String[] items = { "auto", "apfel", "rot", "regen", "birne", "blau",
			"benzin", "gelb", "blaue" };

	JList list = new JList(items);

	JTextField textfeld = new JTextField(20);

	JScrollPane scroll = new JScrollPane(list);

	JPopupMenu pop = new JPopupMenu();

	DefaultCaret dcaret = (DefaultCaret) textfeld.getCaret();

	public TextFieldExtended() {

		list.setFocusable(false);
		scroll.getVerticalScrollBar().setFocusable(false);
		scroll.getHorizontalScrollBar().setFocusable(false);

		scroll.setBorder(null);
		pop.add(scroll);

		add(textfeld);

		setLocationByPlatform(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setVisible(true);

		textfeld.addKeyListener(this);
		pop.addKeyListener(this);

		list.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					textfeld.setText(list.getSelectedValue().toString());
					pop.setVisible(false);
					textfeld.requestFocus();
				} else
					textfeld.setText(list.getSelectedValue().toString());
			}
		});
	}

	public static void main(String[] args) {
		new TextFieldExtended();
	}

	public void keyTyped(KeyEvent e) {

	}

	public void keyPressed(KeyEvent e) {
	}

	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_DOWN:
			list.setSelectedIndex(list.getSelectedIndex() + 1);
			break;
		case KeyEvent.VK_UP:
			list.setSelectedIndex(list.getSelectedIndex() - 1);
			break;
		case KeyEvent.VK_ENTER:
			if (pop.isShowing())
				textfeld.setText(list.getSelectedValue().toString());
			break;
		default: {
			int index = -1;
			if (!textfeld.getText().equals(""))
				index = list.getNextMatch(textfeld.getText(), 1,
						Position.Bias.Forward);

			if (index != -1) {
				list.setSelectedIndex(index);
				pop.setLocation((int) textfeld.getLocationOnScreen().getX()
						+ dcaret.x, (int) textfeld.getLocationOnScreen().getY()
						+ textfeld.getHeight());
				pop.show(textfeld, dcaret.x, textfeld.getY()
						+ textfeld.getHeight());
			} else
				pop.setVisible(false);
			textfeld.requestFocus();

		}
		}
		if (list.getSelectedValue() != null
				&& list.getSelectedValue().equals(textfeld.getText()))
			pop.setVisible(false);
	}
}


Vg Erdal
 
Hallo,

der Thread ist zwar schon ein bißchen älter, aber er verliert dadurch ja nicht an Aktualität.
Habe den Code ein bißchen abgeändert, damit ich gleich richtige Textfelder habe, um sie in ein JFrame oder ähnliches einfach hinfügen und dabei halt die Vorschlagsliste übergeben kann. Mein Problem ist jetzt, dass ich einfach die Koordination, also die Position des PopupMenüs richtig setzen kann. Die x-Koordinate erscheint mir korrekt, aber die y-Koordinate ist falsch. Gezeigt wird es immer sehr weit unter dem entsprechenden Textfeld.
Woran liegt das bzw. wie muss ich das genau abwandeln?
Denke mal, dass ich damit Schwierigkeiten bekomme, dass ich im Frame, wo die Textfelder erstellt und hinzugefügt werden mit einem GridBagLayout arbeite!?
Wie kann ich das gescheit lösen?

Vielen Dank im Voraus

Der abgewandelte Code:

Code:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class TextFieldExtended extends JTextField implements KeyListener {

	String[] items;
	JList list;

	JScrollPane scroll;

	JPopupMenu pop = new JPopupMenu();
	JTextField textfeld = new JTextField();
	DefaultCaret dcaret;

	public TextFieldExtended(String[] test) {

		textfeld = this;
		dcaret = (DefaultCaret) textfeld.getCaret();
		items = test;
		list =  new JList(items);
		scroll = new JScrollPane(list);
		
		list.setFocusable(false);
		scroll.getVerticalScrollBar().setFocusable(false);
		scroll.getHorizontalScrollBar().setFocusable(false);

		scroll.setBorder(null);
		pop.add(scroll);

		textfeld.setVisible(true);
		textfeld.addKeyListener(this);
		pop.addKeyListener(this);
	}

	public void keyTyped(KeyEvent e) {

	}

	public void keyPressed(KeyEvent e) {
	}

	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_DOWN:
			list.setSelectedIndex(list.getSelectedIndex() + 1);
			break;
		case KeyEvent.VK_UP:
			list.setSelectedIndex(list.getSelectedIndex() - 1);
			break;
		case KeyEvent.VK_ENTER:
			if (pop.isShowing())
				textfeld.setText(list.getSelectedValue().toString());
			break;
		default: {
			int index = -1;
			if (!textfeld.getText().equals(""))
				index = list.getNextMatch(textfeld.getText(), 1,
						Position.Bias.Forward);

			if (index != -1) {
				list.setSelectedIndex(index);
				pop.setLocation((int) textfeld.getLocationOnScreen().getX()
						+ dcaret.x, (int) textfeld.getLocationOnScreen().getY()
						+ textfeld.getHeight());
				pop.show(textfeld, dcaret.x, textfeld.getY()+ textfeld.getHeight());
			} else
				pop.setVisible(false);
			textfeld.requestFocus();
		}
		}
		if (list.getSelectedValue() != null
				&& list.getSelectedValue().equals(getText()))
			pop.setVisible(false);
	}
}

Oder den ursprünglichen Code lassen und ein JFrame in ein JFrame einbinden, aber damit bekomme ich Probleme. Geht das überhaupt!?
 
Zuletzt bearbeitet:
Ich hab mal ein paar Sachen geändert und die Position nicht mehr berechnet. Funktioniert dies bei Dir?

Code:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.text.Position;


public class TextFieldExtended extends JTextField implements KeyListener {

  JList list = new JList();
  JPopupMenu pop = new JPopupMenu();

  public TextFieldExtended() {

    JScrollPane scroll = new JScrollPane(list);
    list.setFocusable(false);
    scroll.getVerticalScrollBar().setFocusable(false);
    scroll.getHorizontalScrollBar().setFocusable(false);

    scroll.setBorder(null);
    pop.add(scroll);

    this.setVisible(true);
    this.addKeyListener(this);
    pop.addKeyListener(this);
  }

  /**
   *
   * Methode: keyTyped
   * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
   * 24.05.2007
   *
   * @param e
   */
  public void keyTyped(KeyEvent e) {

  }

  /**
   *
   * Methode: keyPressed
   * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
   * 24.05.2007
   *
   * @param e
   */
  public void keyPressed(KeyEvent e) {
  }

  /**
   *
   * Methode: keyReleased
   * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
   * 24.05.2007
   *
   * @param e
   */
  public void keyReleased(KeyEvent e) {
    switch (e.getKeyCode()) {
      case KeyEvent.VK_DOWN:
        list.setSelectedIndex(list.getSelectedIndex() + 1);
        break;
      case KeyEvent.VK_UP:
        list.setSelectedIndex(list.getSelectedIndex() - 1);
        break;
      case KeyEvent.VK_ENTER:
        if (pop.isShowing()) {
          this.setText(list.getSelectedValue().toString());
        }
        break;
      default: {
        int index = -1;
        if (!"".equals(getText()) && list.getModel().getSize() > 0) {
          index = list.getNextMatch(getText(), 0, Position.Bias.Forward);
        }

        if (index != -1) {
          list.setSelectedIndex(index);
          pop.show(this, 0, getHeight());
        }
        else {
          pop.setVisible(false);
        }
        requestFocus();
      }
    }
    if (list.getSelectedValue() != null && list.getSelectedValue().equals(getText())) {
      pop.setVisible(false);
    }
  }

  /**
   * @return the items
   */
  public ListModel getItems() {
    return list.getModel();
  }

  /**
   * @param items the items to set
   */
  public void setItems(ListModel items) {
    list.setModel(items);
  }

}
 
Hi, super Vorarbeit, ich habe die Klasse mal etwas erweitert...

Die Position des Popups stimmt jetzt und zudem wird nach einem Leerzeichene ein neue Erkennung gestartet.. Ich brauche den Code für eine Eclipse-ähnliche Editorfunktion. Da gibt es ja auch diese Popoupmenüs zur Autovervollständigung..

Ein Problem habe ich aber noch und zwar kann ich mit den Pfeiltasten das Scollpane nicht dazu bringen, automatisch zuscrollen, wenn ich das Ende des SICHTBAREN Liste erreicht habe.. Hat einer eine Idee?

Code:
package combobox;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.text.Position;

public class TextFieldExtended2 extends JTextField implements KeyListener {

	JList list = new JList();
	JPopupMenu pop = new JPopupMenu();
	JScrollPane scroll;

	public TextFieldExtended2( String[] items) {
		
		list = new JList(items);

		scroll = new JScrollPane(list);
		list.setFocusable(false);
		scroll.getVerticalScrollBar().setFocusable(false);
		scroll.getHorizontalScrollBar().setFocusable(false);
		scroll.setBorder(null);

		pop.add(scroll);

		this.setVisible(true);
		this.addKeyListener(this);
		pop.addKeyListener(this);
	}

	/**
	 *
	 * Methode: keyTyped
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 * 24.05.2007
	 *
	 * @param e
	 */
	public void keyTyped(KeyEvent e) {

	}

	/**
	 *
	 * Methode: keyPressed
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 * 24.05.2007
	 *
	 * @param e
	 */
	public void keyPressed(KeyEvent e) {
	}

	/**
	 *
	 * Methode: keyReleased
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 * 24.05.2007
	 *
	 * @param e
	 */
	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_DOWN:
			list.setSelectedIndex(list.getSelectedIndex() + 1);
			break;
		case KeyEvent.VK_UP:
			list.setSelectedIndex(list.getSelectedIndex() - 1);
			break;
		case KeyEvent.VK_ENTER:
			if (pop.isShowing()) {
				this.setText(getLastSentence() + list.getSelectedValue().toString());
			}
			break;
		default: {
			int index = -1;
			if (!"".equals(getText()) && list.getModel().getSize() > 0) {
				index = list.getNextMatch(getLastWord(), 0, Position.Bias.Forward);
			}

			if (index != -1) {
				list.setSelectedIndex(index);
				int y = (int)getCaret().getMagicCaretPosition().getY() + 15;
				int x = (int)getCaret().getMagicCaretPosition().getX();
				pop.show(this, x, y);
			}
			else {
				pop.setVisible(false);
			}
			requestFocus();
		}
		}
		if (list.getSelectedValue() != null && list.getSelectedValue().equals(getLastWord())) {
			pop.setVisible(false);
		}
	}
	
	private String getLastSentence(){
		String result="";
		String text = getText();
		if(!text.equals("")){
			int index = text.lastIndexOf(getLastWord());
			result = text.substring(0,index);
		}
		return result;
	}
	
	private String getLastWord(){
		String result="";
		String text = getText();
		if(!text.equals("")){
			String[] textes = text.split(" ");
			result = textes[textes.length-1];
		}
		
		return result;
	}

	/**
	 * @return the items
	 */
	public ListModel getItems() {
		return list.getModel();
	}

	/**
	 * @param items the items to set
	 */
	public void setItems(ListModel items) {
		list.setModel(items);
	}


}

Viele Grüße,
offtake
 
Ich habe einen Workaround gefunden, jedoch ist der recht dirty...

Code:
		case KeyEvent.VK_DOWN:
			list.setSelectedIndex(list.getSelectedIndex() + 1);
			JViewport view = scroll.getViewport();
			Point p = new Point(view.getX(),list.getSelectedIndex()*2);
			view.setViewPosition(p);
			break;

Habt ihr ne Idee wie ich das anders mache, ich will ja auf keinen Fall als dem Index ne Pixelzahl errechnen, wer weiß auf welchem Rechner das klappt und wo nciht...

Mit dem Fokuskram haut das auch keinen Fall hin, weil es dann wieder Probleme mit der Abfrage der Entertaste gibt...

vg, offtake
 
Hi!
Leider ist der Thread schon etwas älter, hoffe trotzdem, dass er noch beachtet wird. :)
Ich habe euren Code nun mal als Vorlage für meine AutoCompletion verwendet und für mich dann noch etwas angepasst. Ein Problem habe ich jedoch, welches ich bislang noch nicht lösen könnte.
Mein Wunsch wäre es, dass die Breite des PopUp-Fensters und des Textes, der sich darauf befindet, die gleiche Breite hat, wie mein Textfield. Bislang sieht es nämich so aus:
Beim PopUp kann ich die Größe ändern, allerdings nicht die der Liste. Somit sehe ich den grauen Hintergrund des PopUps, in der Mitte befindet sich dann die weiße Liste mit dem Text der aufgepoppt ist. Bislang habe ich vergebens versucht, den Text und dessen weißen Hintergrund auf das gesamte PopUp zu verteilen.

Habt ihr eine Idee, wie ich das hinbekommen könnte?

Gruß
 
Zurück