# keylistener auf jtable



## java_starter_dl (13. Mai 2008)

Hi leuz!
Brauch wieder mal ein bisschen hilfe...

Ich habe eine jTable, in der Personaldaten angezeigt werden. Wenn eine Zeile selektiert wird, müssen gewisse Daten dieser Zeile ausgelesen werden. Ich habe das mit einem MouseListener gelöst.

Nun habe ich das Problem, wenn der User mit den Pfeil-Tasten die Tabelle durchsucht passiert natürlich gar nix!
Welchen Listener kann man da für die up and down Tasten nehmen, und welche Methode davon muss ich überschreiben?

hier ist mein Code für den Mouse listener:


```
this.jTbPersonaldaten.addMouseListener(new java.awt.event.MouseAdapter() 
        { 
            @Override
            public void mouseClicked(java.awt.event.MouseEvent evt) 
            { 
                Personaldaten_Selection(); 
            } 
        }
        );
```


Bin dankbar für jede Hilfe!
lg


----------



## Niki (13. Mai 2008)

Du verwendest generell den falschen Listener. Das macht man nicht über Mouse- Keylistener, sondern über einen ListSelectionListener

Das schaut dann so aus:

```
table.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
  public void valueChanged(ListSelectionEvent e){

  }
});
```


----------



## java_starter_dl (13. Mai 2008)

ah ok, thx!
Da is dann des mit den key-up un down auch abgedeckt!
Werd ich gleich mal ausporbieren! Danke niki!


----------



## java_starter_dl (14. Mai 2008)

Hi! Hab die Listener jetzt so verändert wie du mir das geschildert hast. Jetzt habe ich das Problem, dass jedes mal wenn der User den Value in der Tabelle verändert, der listener 2 mal ausgeführt wird! Kann mir das jemand erklären?
Das soll er nämlich nicht, denn sonst stimmt meine Logik die ich in der Funktion habe die ich im Listener aufrufe nicht mehr...

Danke schon mal!
lg


----------



## Niki (14. Mai 2008)

Probier mal das:

```
table.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
  public void valueChanged(ListSelectionEvent e){
    if(e.getValueIsAdjusting()){
      //hier deine Logik ausführen
    }
  }
});
```


----------



## java_starter_dl (14. Mai 2008)

ok, du bist ziemlich gut! 

Leider wird die if-Bedingung nicht erfüllt wenn eine Zeile selektiert wird, die bereits makiert ist.

Ich sag dir schnell wozu ich das brauche: 
Ich habe da eine Spalte in der Tabelle die den Status des Datensatzes angibt. Entweder aktiv oder inaktiv. Hab das simpel gelöst indem ich jedesmal wenn der User auf die Spalte klickt ein 'X' reinschreibe, oder wenn bereits ein 'X' drinn steht, wird es eben gelöscht.


----------



## Niki (14. Mai 2008)

Das solltest du dann anders lösen:

Im TableModel überschreibst du die Methoden getColumnClass(int), isCellEditable(int, int) und setValueAt(Object, int, int)

Bei getColumnClass gibst du für die aktiv-Spalte Boolean.class zurück. (für den Rest halt die dazugehörige Klasse)

isCellEditable gibt true für die aktiv-Spalte zurück

setValueAt setzt vom Objekt den übergebenen Wert. Ich poste dir mal ein Beispiel welches du laufen lassen kannst:


```
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;

public class MyFrame extends JFrame {

	private TableModel<TableObject> model = null;
	private JTable table = null;

	public MyFrame() {
		super("Table Demo");
		guiInit();
		pack();
		setLocationRelativeTo(null);
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

		fillTable();
	}

	private void guiInit() {
		Container cont = getContentPane();
		cont.setLayout(new BorderLayout());	

		model = new TableModel<TableObject>(new String[] { "Values", "Active" }) {
			public Object getValueAt(int rowIndex, int columnIndex) {
				switch (columnIndex) {
				case 0:
					return getElementAt(rowIndex).getValue();
				case 1:
					return getElementAt(rowIndex).isActive();
				}
				return null;
			}

			@Override
			public Class getColumnClass(int columnIndex) {
				switch (columnIndex) {
				case 0:
					return String.class;
				default:
					return Boolean.class;
				}
			}
			
			@Override
			public boolean isCellEditable(int rowIndex, int columnIndex) {
				return columnIndex == 1;
			}
			
			@Override
			public void setValueAt(Object value, int rowIndex, int columnIndex) {
				TableObject to = getElementAt(rowIndex);
				to.setActive((Boolean)value);
				fireTableRowsUpdated(rowIndex, rowIndex);
			}
		};

		table = new JTable(model);

		JScrollPane scroller = new JScrollPane();
		scroller.getViewport().add(table);
		
		cont.add(scroller, BorderLayout.CENTER);	
	}

	private void fillTable() {
		List<TableObject> content = new ArrayList<TableObject>();
		for (int i = 0; i < 50; i++) {
			content.add(new TableObject("Value" + i));
		}
		model.setContent(content);

	}

	private class TableObject {
		private String value = null;
		private boolean selected = false;
		private boolean active = true;

		public boolean isActive() {
			return active;
		}

		public void setActive(boolean active) {
			this.active = active;
		}

		public TableObject() {

		}

		public TableObject(String value) {
			setValue(value);
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}

		public boolean isSelected() {
			return selected;
		}

		public void setSelected(boolean selected) {
			this.selected = selected;
		}

	}

	public static void main(String[] args) {
		new MyFrame().setVisible(true);
	}

}
```

Und hier noch das TableModel

```
import java.util.ArrayList;
import java.util.List;


import javax.swing.table.AbstractTableModel;

public abstract class TableModel<T> extends AbstractTableModel {

	private List<T> content = null;
	private String[] header = null;

	public TableModel(List<T> content, String[] header) {
		this.content = content;
		this.header = header;
	}

	public TableModel(String[] header) {
		this(new ArrayList<T>(), header);
	}

	public List<T> getContent() {
		return content;
	}

	public void setContent(List<T> content) {
		this.content = content;
		this.fireTableDataChanged();
	}

	public void addElement(T o) {
		int pos = content.size();
		content.add(o);
		this.fireTableRowsInserted(pos, pos);
	}

	public void editElement(T oldo, T newo) {
		int pos = content.indexOf(oldo);
		if (pos == -1) {
			return;
		}

		content.remove(oldo);
		content.add(pos, newo);
		this.fireTableRowsUpdated(pos, pos);
	}

	public void editElement(int pos, T newo) {
		content.remove(pos);
		content.add(pos, newo);
		this.fireTableRowsUpdated(pos, pos);
	}

	public void deleteElement(T o) {
		int pos = content.indexOf(o);
		if (pos == -1) {
			return;
		}

		content.remove(o);
		this.fireTableRowsDeleted(pos, pos);
	}

	public void deleteElement(int pos) {
		content.remove(pos);
		this.fireTableRowsDeleted(pos, pos);
	}

	public int getColumnCount() {
		return header.length;
	}

	public String getColumnName(int col) {
		return header[col];
	}

	public int getRowCount() {
		return content.size();
	}

	public T getElementAt(int index) {
		return content.get(index);
	}	

}
```

Dieser Link könnte dir auch noch helfen: How_to_use_Tables


----------



## java_starter_dl (14. Mai 2008)

du überforderst mich da jetzt ein bisschen    , aber ich versuchs mal, ist auf jedenfall eine optisch schönere Lösung!
Danke erstmal...


----------



## Niki (14. Mai 2008)

Du packst das schon. Ist nicht so schwer und wenn du Fragen hast brauchst du sie nur zu stellen. Wichtig ist halt dass du auf jeden Fall dein eigenes TableModel verwendest, sonst kommst du irgendwann in Teufels Küche


----------



## java_starter_dl (14. Mai 2008)

hab das jetzt mal versucht so umzusetzen, und dabei mein Programm ziemlich über den Haufen geworfen. Ein Problem hab ich noch, vielleicht kennst du es ja: mir wird anstatt der Checkboxen der Text true und false angezeigt. Wenn ich darauf klicke, wird ganz kurz die Checkbox angezeigt.
Idee?


----------



## java_starter_dl (14. Mai 2008)

Ach, hab den fehler schon gefunden. Hatte auf die Spalte noch irgendwo einen CellRenderer gesetzt. jetzt funktioniert das. Mal sehen wies weiter geht....


----------



## java_starter_d alias Phil (14. Mai 2008)

neue Frage... sorry dass ich dich so in anspruch nehme...

in welche Methode springt er hin, wenn sich die Checkbox verändert?, denn dann muss ich etwas in der Datenbank tun.
Im Moment ist es so, dass der Listener schreit, wenn ich auf die Chechbox klicke, und in der Methode die der Listener aufruft guck ich mal nach ob die Checkboxen jetzt true oder false sind. Je nachdem führe ich dann irgendetwas in der Datenbank aus.
Aber da kommt wieder das Problem von vorhin: Wenn ich jetzt mehrmals auf die Checkbox klicke, verändert sich die Checkbox zwar, aber der Listener wird nur einmal ausgeführt da es immer die gleiche Zeile ist...

Anderer Listener?


----------



## Niki (14. Mai 2008)

Das mit der Datenbank halte ich für keine gute Idee. Du solltest erst beim Klicken auf Speichern in die Datenbank schreiben. Sonst ist das ja ein ganz schöner Performancekiller. Wenn du die CheckBox anklickst wird die Methode setValueAt im TableModel aufgerufen. Dort wird dann der neue Wert vom Objekt gesetzt.


----------



## java_starter_Phil (14. Mai 2008)

das layout ist leider so vorgegeben, und die performance ist dabei kein problem (Schnelle Verbindung, Sehr Guter Oracle Server).
Das mit dem setValue werde ich dann verwenden, aber fällt dir nicht noch ein anderer Listener ein?

Mir ist da noch ein anderer Lösungsansatz eingefallen:
Wie wärs, wenn ich zusätzlich einen Mouse-Listener mache, und falls sich der wert der Table nicht verändert hat soll er eben das tun was sonst das valueChanged gemacht hat... Dazu muss ich allerdings prüfen ob sich der Wert verändert hat ... geht das irgendwie?

danke vielmals nochmal!


----------



## Niki (14. Mai 2008)

Naja, ich find MouseListener bei einer JTable nicht sehr schön (außer bei double-Klick). Was genau hast du denn vor? Willst du jedes mal beim Ändern des Models in der Datenbank etwas ändern? Wenn ja könnte dir dieser Listener auch noch helfen: TableModelListener


----------



## java_starter_Phil (14. Mai 2008)

Ok, ich versuche dir jetzt zu erklären was ich machen möchte... hoff ich schaff das irgendwie verständlich:

Ich habe eine Tabelle mit Berechtigungen. Diese Tabelle hat folgende Spalten:
USBNR: das ist die Nummer der Berechtigung
Beschreibung: ...der Berechtigung
Status: ... ist die Berechtigung aktiv oder inaktiv
Einschränkung: Auf jede Berechtigung können beliebig viele Einschränkungen definiert werden die hier angezeigt werden.


Der Workflow sieht folgendermaßen aus:
User wählt eine Berechtiung. 
User setzt Berechtigung aktiv. (Berechtigung wird in der Datenbank aktiv gesetzt)
User klickt auf die Spalte Einschränkung der einzuschränkenden Berechtigung (nur möglich wenn Berechtigung aktiv ist). 
Ein Dialog öffnet sich. 
User wählt Einschränkungen aus. 
User schließt Dialog. (ausgewählte Einschränkungen werden der Berechtigung in der Datenbank zugeordnet)
Tabelle wird aktualisiert.


hoff man kann das irgendwie verstehen...   ???:L 

lg


----------



## Niki (14. Mai 2008)

Da hast du meiner Meinung nach zwei Möglichkeiten das schön zu lösen:

Entweder du baust dir zum Bearbeiten einer Berechtigung einen Dialog, wo alle relevanten Daten angezeigt werden. Beim Bestätigen des Dialogs werden die Änderungen in die Datenbank geschrieben und die Änderungen ins TableModel übernommen. Der Dialog wird über einen Doppelklick auf die Tabelle angezeigt und mit der selektierten Zeile befüllt.

Die andere Möglichkeit ist dass du alle Berechtigungen bearbeiten kannst und einen Speichern-Button anbietest. Beim Speichern wird überprüft was sich geändert hat und nur die Änderungen in die Datenbank übernommen. Dies ist meiner Meinung nach aber die viel schwierigere Option, da du alle Änderungen irgendwie mitbekommen musst.

Falls du es aber auf deine Art machen möchtest sollte der TableModelListener hilfreich sein.


----------



## java_starter_Phil (14. Mai 2008)

da hast du wahrscheinlich recht. TableModelListener will eh net so richtig, also mach ich es mit doppelklick auf die Zeile. Wie mach ich denn das mit dem Doppelklick? Wieder mit MouseListener? Gibts da einen eigenen für Doppelklick?

lg


----------



## Michael... (14. Mai 2008)

MouseEvent.getClickCount()>=2


----------



## java_starter_Phil (14. Mai 2008)

ja, hab ich auch so gelöst!
Jetzt müsst ich eigentlich allein klar kommen... Vielen Dank niki, du hast mir sehr weitergeholfen!  :toll: 
bis bald.... (hoffentlich nicht allzu bald  :wink:   )


----------

