JTable editierbar, Enter Event,...

Status
Nicht offen für weitere Antworten.

Robinson

Mitglied
Hi,

ich code schon ein paar Stunden an einer Komponente rum und komme nicht zu dem Ergebnis dass ich gerne hätte.

Meine Vorstellung:


Eine JTable zum Erfassen von Artikelpreisen:

Spalte 1: Artikelnummer
Spalte 2: Beschreibung
Spalte 3: Preis

Gewünschtes Verhalten:

- ich möchte die Zellen direkt editieren können ohne erst einen Doppelklick machen zu müssen.
- nach der Eingabe der Artikelnummer sollte in einer Datenbank nach dem Artikel gesucht werden und wenn vorhanden eingetragen (Fokus auf Preisfeld)
- Beim Drücken von Return sollte der Fokus in die nächste Spalte und am Ende der Zeile in die nächste Zeile springen
- Beim Auswählen einer Zelle sollte der Inhalt bereits selektiert werden damit er direkt überschrieben werden kann.


Was ich habe:

Den Artikel suchen

- habe ich im Model über die Methode setValueAt realisiert.
ich frage die Spalte ab und reagiere entsprechend (Funktionsaufruf, "Daten laden")


die Zeilen direkt editieren

- habe ich realisiert durch den Aufruf von
Code:
((DefaultCellEditor)table.getDefaultEditor(Object.class)).setClickCountToStart(1);

bei Enter in nächste Spalte

- habe ich über einen KeyListener bei der Table versucht, ohne Erfolg.
- Das Event der Componente wird scheinbar ausgeführt, aber der Focus ändert sich nicht.

bei Focus Inhalt selektieren

- ich habe der TextField Komponente einen FocusListener gegeben aber das hat nichts bewirkt
 
Das mit dem bei Enter in nächstes Feld habe ich auch inzwischen gefunden,
zumindest fast.

Dieser Thread behandelt ein entsprechendes Beispiel:
www.java-forum.org/de/viewtopic.php?t=28907


Das funktioniert auch soweit, aber leider muss ich beim Verlassen der Zelle zwei Mal Enter drücken.
Mit dem ersten mal beendet sich der Edit Mode mit dem zweiten mal springt er mit dem Focus ins nächste Feld.


Wie kann ich meinem CellEditor klar machen dass er beim Enter Press in die nächste Spalte springen soll?
 
I got it!

😀

Also, für die Welt da drausen 😉


Lösung für: die Zelle direkt editieren, Tabs innerhalb der Tabelle, bei onFocus Inhalt selektieren


Eigener CellEditor:

Code:
import java.awt.Component;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;

class MyTextEditor extends JTextField implements TableCellEditor {

	private static final long serialVersionUID = 1L;

	private List listeners = new ArrayList();

	// Standardkonstruktor
	public MyTextEditor() {
		addFocusListener(MyFocusListener.get());
		setBorder(BorderFactory.createEmptyBorder());
	}

	// Möglicherweise möchte jemand über Ereignisse des Editors
	// informiert werden
	@SuppressWarnings("unchecked")
	public void addCellEditorListener(CellEditorListener l) {
		listeners.add(l);
	}

	// Ein CellEditorListener entfernen
	public void removeCellEditorListener(CellEditorListener l) {
		listeners.remove(l);
	}

	// Gibt den aktuellen Wert des Editors zurück.
	public Object getCellEditorValue() {
		return getText();
	}

	// Gibt eine Component zurück, welche auf dem JTable dargestellt wird,
	// und mit der der Benutzer interagieren kann.
	public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
		Vector v = (Vector)((DefaultTableModel)table.getModel()).getDataVector().get(row); 
		setText((String)v.get(column));
		return this;
	}

	// Gibt an, ob die Zelle editierbar ist. Das EventObject kann
	// ein MouseEvent, ein KeyEvent oder sonst was sein.
	public boolean isCellEditable(EventObject anEvent) {
		return true;
	}

	// Gibt an, ob die Editor-Component selektiert werden muss, um
	// sie zu benutzen. Diese Editor soll immer selektiert werden,
	// deshalb wird hier true zurückgegeben
	public boolean shouldSelectCell(EventObject anEvent) {
		return true;
	}

	// Bricht das editieren der Zelle ab
	public void cancelCellEditing() {
		fireEditingCanceled();
	}

	// Stoppt das editieren der Zelle, sofern möglich.
	// Da der JSpinner immer einen gültigen Wert anzeigt, kann auch
	// jederzeit gestoppt werden (return-Wert = true)
	public boolean stopCellEditing() {
		fireEditingStopped();
		return true;
	}

	// Benachrichtig alle Listener, dass das Editieren abgebrochen wurde
	protected void fireEditingCanceled() {
		ChangeEvent e = new ChangeEvent(this);
		for (int i = 0, n = listeners.size(); i < n; i++)
			((CellEditorListener) listeners.get(i)).editingCanceled(e);
	}

	// Benachrichtig alle Listener, dass das Editieren beendet wurde
	protected void fireEditingStopped() {
		ChangeEvent e = new ChangeEvent(this);
		for (int i = 0, n = listeners.size(); i < n; i++)
			((CellEditorListener) listeners.get(i)).editingStopped(e);
	}
}

FocusListener:

Code:
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.text.JTextComponent;

public class MyFocusListener implements FocusListener {

	public void focusGained(FocusEvent focusevent) {
		JTextComponent jtextcomponent = (JTextComponent) focusevent.getComponent();
		jtextcomponent.setSelectionStart(0);
		jtextcomponent.setSelectionEnd(jtextcomponent.getText().length());
	}

	public void focusLost(FocusEvent focusevent) {
	}

	private MyFocusListener() {
	}

	public static MyFocusListener get() {
		if (fl == null)
			fl = new MyFocusListener();
		return fl;
	}

	public static MyFocusListener fl = null;

}


Die abgeleitete Tabellenkomponente:

Code:
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.table.TableModel;

public class EditorTable extends JTable {

	private static final long serialVersionUID = 1L;
	
	public EditorTable() {
		super();
		init();
	}
	
	public EditorTable(TableModel model) {
		super(model);
		init();
	}
	
	private void init() {
		
		this.setDefaultEditor(Object.class, new MyTextEditor());
		
		// "Enter"-Taste bekommt die Funktion der "Tab"-Taste
        InputMap im = getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
        KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
        Object tabFunktion = im.get(tab);
        im.put(enter, tabFunktion);
        
        //  Das übliche "Tab" Verhalten überschreiben:
        //  Auf die nächste editierbare Zelle springen;
        //  wenn keine editierbare Zellen vorhanden, auf nächste Zelle gehen.
        final Action alteTabAktion = getActionMap().get(tabFunktion);
        Action tabAktion = new AbstractAction() {

        	private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				JTable tabelle = (JTable)e.getSource();
				alteTabAktion.actionPerformed( e );
				
				tabelle.editCellAt(tabelle.getSelectedRow(),tabelle.getSelectedColumn());
            }
        };
        getActionMap().put(tabFunktion, tabAktion);
        addKeyListener(new KeyAdapter(){
            public void keyReleased(KeyEvent e){
                enterKeyReleased(e);
            }
        });

	}
	
    private void enterKeyReleased(KeyEvent e){
        if(getCellEditor()!=null){
            getEditorComponent().requestFocusInWindow();
        }
    }

}



Die obigen Klassen basieren auf verschiedenen Codes aus diesem Forum.
Ich möchte ja nicht die Leistung Anderer als meine eigene darstellen.


Lösung für: den Artikel suchen

Code:
	private DefaultTableModel tableModel = new DefaultTableModel() {
		public boolean isCellEditable(int i, int j) {
			return true;
		}
		
		@SuppressWarnings("unchecked")
		public void setValueAt(Object value, int row, int col) {
			
			if (col==0) {
				if (table.isEditing()) selectArticleByProducerId(value, row);
			}
			if (col==1) {
				selectArticleBySupplierId(value, row); 
			}
			((Vector)getDataVector().get(row)).set(col, value);
			
			if (!lastRowEmpty()) addEmptyRow();
		}
		private static final long serialVersionUID = 1L;
	};

Das basiert jetzt tatsächlich auf meinem Mist 🙂


Ich habe keine Ahnung ob dieser Code für irgendwen von Nutzen ist?
Mir hat das einen ganz schön nervigen tag gebracht.
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben