ein "JLabel" mit Doppelklick editieren.

  • Themenstarter Themenstarter Go
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.

Go

Mitglied
Hallo, ich bin noch ein Java-Anfänger, dennoch würde ich folgendes realisieren:

im Normalzustand ist ein Bedienelement äußerlich kaum von JLabel zu unterscheiden,
durch ein Doppelklick wird dieser zum JTextField und kann editiert werden. Durch das
Drücken von Enter wird die Änderung wirksam, durch das Drücken von ESC oder
Woandersklicken verworfen. Natürlich möchte ich ein Dutzend solcher Elemente im
Frame haben.

So wie ich es mir überlegt habe, wird es mit JTextField und seinen Methoden
setOpaque(false) und setBorder(BorderFactory.createEmptyBorder()) klappen.
Nun, mit Listener kenne ich mich noch nicht gut aus, da würde ich für ein paar gute
Ratschläge sehr dankbar sein.

Ausserdem google ich nach Beispielen, denn das sollte ja eigentlich nicht etwas
außergewöhnliches sein, und bis jetzt habe ich eins gefunden, was halbwegs passt,
es ändertet die Tabnamen in JtabbedPane. hier das Beispiel. ich konnte es aber
nicht nach meinen Wünschen umbauen.
 
hi, also du musst ein mouselistener an das label hängen.
ClickCount()==2 -> doppelklick.
Hier ein einfaches beispiel. bei doppelklick wird ein inputdialog geöffnet wo der text für das label eingetragen werdne kann, wie du das dann umsetzt ist dir überlassen ;D

Java:
label.addMouseListener(new MouseAdapter() {

			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					String s = (String) JOptionPane.showInputDialog("Eingabe:");

					if ((s != null) && (s.length() > 0)) {
						label.setText(s);
						return;
					}
				}

			}
		});
 
Zuletzt bearbeitet:
Danke schön, ich hab jetzt folgendes ausprobiert:
Java:
	JTextField editableLabel = new JTextField();
	editableLabel.setOpaque(false);
    	editableLabel.addFocusListener(new FocusListener() {
			
			@Override
			public void focusLost(FocusEvent e) {
				// TODO Auto-generated method stub
				((JTextField) e.getSource()).setBorder(BorderFactory.createEmptyBorder());
				((JTextField) e.getSource()).setOpaque(false);
			}
			
			@Override
			public void focusGained(FocusEvent e) {
				// TODO Auto-generated method stub
				((JTextField) e.getSource()).setBorder(BorderFactory.createBevelBorder(1));
				((JTextField) e.getSource()).setOpaque(true);
			}
		});

Das ist ein guter Anfang, aber wie könnte man das schöner machen? also z.B. von JTextField erben und dieses Verhalten in eine neue Elementenart implementieren und nur Instanzen von diesen Element benutzen. und kann man überhaupt Listener in die Elementenimplementation einführen? . und wie realisiert man effizient Eingabeanbruch mit der darauf folgender Herstellung des alten Wertes? (erste Idee, falls man schon ein JTextField erweitert, dann noch irgendein Klassenmember einführen und darein speichern)
 
hab jetzt was passendes gemacht, ich implementierte einen eigenen Listener:

TextFieldEditListener.java
Java:
import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JTextField;

public class TextFieldEditListener extends MouseAdapter implements FocusListener, KeyListener{

	@Override
	public void focusGained(FocusEvent e) {
	}

	@Override
	public void focusLost(FocusEvent e) {
		endEdit((JTextField) e.getSource());
	}
	
	public void mouseClicked(MouseEvent e) {
		if(e.getClickCount()==2) {				     				    
			startEdit((JTextField) e.getSource());
		}
	}

	//Bereite das JTextField vor und speichere den alten Text
	void startEdit(JTextField j){
		((EditableLabel)j).saveOldText();
		j.setBorder(BorderFactory.createLineBorder(Color.black));
		j.setOpaque(true);
		j.setEditable(true);
	}

	//Routine die den alten Wert des JTextField wiederherstellt.
	void cancelEdit(JTextField j){
		j.setText(((EditableLabel)j).getOldText());
		endEdit(j);
	}

	// JTextField wird unscheinbar gemacht.
	void endEdit(JTextField j)	{
		j.setBorder(BorderFactory.createEmptyBorder());
		j.setOpaque(false);
		j.setSelectionEnd(0);
		j.setEditable(false);	
	}

	@Override
	public void keyPressed(KeyEvent e) {
		 if(e.getKeyCode()==KeyEvent.VK_ENTER) {
			 endEdit((JTextField) e.getSource());
		 }else if(e.getKeyCode()==KeyEvent.VK_ESCAPE) {
		         cancelEdit((JTextField) e.getSource());
	     }
	}

	@Override
	public void keyReleased(KeyEvent e) {		
	}

	@Override
	public void keyTyped(KeyEvent e) {
	}
}


die JTextField werden durch Doppelklick aktiv, und durch Fokusverlust wieder passiv. es funktionieren das Verlassen des JTextField durch Enter und das Abrechen durch ESC. Dafür bastelte ich eine neue Klasse, die von JTextField erbte und ein String-Member für den alten Wert bereithält.

EditableLabel.java
Java:
import javax.swing.BorderFactory;
import javax.swing.JTextField;

public class EditableLabel extends JTextField {

	private String oldText;
	
	public EditableLabel()
	{	
		super();
		init();
	}

	public EditableLabel(String string) {
		super(string);
		init();
	}
	
	void init()
	{
		setBorder(BorderFactory.createEmptyBorder());
		setOpaque(false);
		setEditable(false);
		String oldValue = new String();
				
	}

	public String getOldText() {
		return oldText;
	}

	public void setOldText(String oldText) {
		this.oldText = oldText;
	}
	
	public void saveOldText() {
		this.oldText = this.getText(); // ich habe ein Gefühl, dass das so nicht koscher ist.
	}

}


Es kommen einige Seiteneffekte wie z.B. das Fehlen des Cursors und durch ein Weg-Klick (also auf irgendwas, was nicht das aktive Element ist) verliert mein JTextField nicht den Fokus.

hier die GUI zum Testen:
TestEditableLabel.java
Java:
import java.awt.Color;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class TestEditableLabel extends JFrame{

	TestEditableLabel(){
	
	JTextField editableLabel1 = new EditableLabel("eins     ");
	JTextField editableLabel2 = new EditableLabel("zwo      ");
	JTextField editableLabel3 = new EditableLabel("drei     ");
	JTextField editableLabel4 = new EditableLabel("vier     ");
	
	TextFieldEditListener myTextFieldEditListener = new TextFieldEditListener();
	
	editableLabel1.addFocusListener(myTextFieldEditListener);
	editableLabel2.addFocusListener(myTextFieldEditListener);
	editableLabel3.addFocusListener(myTextFieldEditListener);
	editableLabel4.addFocusListener(myTextFieldEditListener);
	
	editableLabel1.addKeyListener(myTextFieldEditListener);
	editableLabel2.addKeyListener(myTextFieldEditListener);
	editableLabel3.addKeyListener(myTextFieldEditListener);
	editableLabel4.addKeyListener(myTextFieldEditListener);
	
	editableLabel1.addMouseListener(myTextFieldEditListener);
	editableLabel2.addMouseListener(myTextFieldEditListener);
	editableLabel3.addMouseListener(myTextFieldEditListener);
	editableLabel4.addMouseListener(myTextFieldEditListener);	
	
	JPanel A = new JPanel();
	A.setBackground(Color.gray);
	
	A.add(editableLabel1);
	A.add(editableLabel2);
	A.add(editableLabel3);
	A.add(editableLabel4);
	
	add(A);
	
	setSize(400,400);
    setLocationRelativeTo(null);
    setVisible(true);
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    pack();
	}
	
	public static void main(String[] args) {
		TestEditableLabel a = new TestEditableLabel();
	}

}

Außerdem bin ich noch ein Java-Noob und fühle, dass ich das Ganze nicht optimal gemacht habe, und da habe ich noch einige Fragen:
  • ist das ok, dass ich einige Male in TextFieldEditListener die JTextField caste und nicht mit EditableLabel arbeite?
  • die Methode saveOldText() aus EditableLabel verwendet eine Stringzuweisung, ist das so nicht böse?
  • wie bekomme ich die Seiteneffekte los?
  • kann man Adapter implementieren damit ich in TextFieldEditListener diese vielen leeren Methoden los werde?
  • was kann man optimieren?

ps: sorry, dass es alles nicht kommentiert ist
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben