D) JTable – Momentan editierte Zelle abfragen

Vielleicht kennen Sie das Problem? Sie haben eine editierbare JTable eingebunden, und möchten die eingegebenen Werte bspw. nach einem Klick auf einen JButton abfragen, verarbeiten oder speichern. Leider hat der User zuvor noch eine Zelle editiert, so dass diese beim Klick auf den JButton noch aktiv war. Dies hat zur Folge, dass in der momentan editierte Zelle beim Auslesen noch der alte Wert, nicht aber die Benutzereingabe steht. In diesem Kapitel zeigen wir Ihnen die Lösung dieses Problems.

Das Problem

Zum besseren Verständnis bauen Sie zuerst das Problem nach. Kompilieren und führen Sie hierzu diesen Code aus:

package de.jbb.table;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class JTableProblem {

  private static JFrame frame;
  private static JTable table;
  private static JButton readValues;

  public static void main(String[] args) {

    JTableProblem.frame = new JFrame();
    JTableProblem.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JTableProblem.frame.setLayout(new BorderLayout());

    String[][] content = new String[][] { 
        {"Value 1/1", "Value 1/2", "Value 1/3"}, 
        {"Value 2/1", "Value 2/2", "Value 2/3"}, 
        {"Value 3/1", "Value 3/2", "Value 3/3"} 
      };
    String[] head = new String[] {"Column1", "Column2", "Column3"};

    JTableProblem.table = new JTable(content, head);
    JTableProblem.readValues = new JButton("Read");

    JTableProblem.readValues.addActionListener(JTableProblem.al);

    JTableProblem.frame.add(new JScrollPane(JTableProblem.table));
    JTableProblem.frame.add(JTableProblem.readValues, BorderLayout.SOUTH);

    JTableProblem.frame.pack();
    JTableProblem.frame.setVisible(true);
  }

  private static ActionListener al = new ActionListener() {

    public void actionPerformed(ActionEvent arg0) {

      for (int y = 0; y < JTableProblem.table.getRowCount(); y++) {
        for (int x = 0; x < JTableProblem.table.getColumnCount(); x++) {
          System.out.println("Value " + (x + 1) + "/" + (y + 1) + "=" + JTableProblem.table.getValueAt(x, y));
        }
      }
    }
  };
}&#91;/sourcecode&#93;

Es wird eine Tabelle mit editierbaren Zellen erzeugt. Wenn Sie auf <em>Read</em> klicken, werden die Zelleninhalt ausgelesen und untereinander aufgelistet. Dies funktioniert soweit ohne Probleme. Überschreiben Sie jetzt die erste Spalte der ersten Zeile mit einem anderen Wert und klicken Sie anschließend <strong>sofort</strong> auf <em>Read</em> (eben so, wie es ein User Ihrer Anwendung auch machen würde). Sie werden feststellen, dass dieser neue Wert nicht übernommen wurde, und dass stattdessen der alte Wert ausgegeben wird.

<strong>Die Lösung</strong>

Der neue Wert wird erst dann übernommen, wenn der User vorher das Editieren der Zelle beenden würde, indem er z. B. in eine andere Zelle klickt. Dies können Sie aber selbstverständlich nicht von Ihren Usern verlangen! Deshalb benötigen Sie eine Lösung auf Programmiererebene, die beim Speichern oder Verlassen der Tabelle das Editieren beendet. Hierzu bieten sich zwei Möglichkeiten an:

<strong>Die Universal-Lösung - Editieren beim Verlassen der JTable beenden</strong>

Mit dieser Lösung fangen Sie das Problem an der Wurzel ab. Sobald der User die <code>JTable</code> verlässt, die <code>JTable</code> also den Fokus verliert, wird das Editieren der aktuellen Zelle abgebrochen und der Inhalt "festgeschrieben", so dass er später durch Sie abfragbar ist. Hierzu müssen Sie eine Property der Tabelle verändern. Fügen Sie folgende Zeile bei der Initialisierung Ihrer <code>JTable</code> ein:

JTableProblem.table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

Beachten Sie aber, dass diese Property nicht von jeder Runtime Environment unterstützt werden muss!

Editieren der Zelle beim Button-Klick abbrechen

Eine aufwändigere, da vor jedem Auslesen anzuwendende, aber sicherere Methode ist es, den Editor der JTable anzuweisen, bevor die Daten ausgelesen werden, das Editieren abzubrechen. Fügen Sie folgende Zeile vor dem Auslesen des Inhalts ein (in unserem Fall im ActionListener vor der äußeren for-Schleife):

JTableProblem.table.getDefaultEditor(Object.class).stopCellEditing();

Ersetzen Sie hierbei ggf. Object.class durch die Klasse, die der Editor bearbeiten soll.

5 Replies to “D) JTable – Momentan editierte Zelle abfragen”

  1. Marcus

    Hallo Java-Blog-Buch Autoren,

    der Tipp ist einfach nur klasse und findet bei meinen Programmen nun häufige Verwendung.

    Viele Grüße
    Marcus

  2. marcel

    Könnte man das ganze nicht auch mit einem normalen FocusListener machen?
    Also

    JTableProblem.table.addFocusListener(this);

    und dann müsste er wenn man auf die Ausgabe klickt den Fokus ja automatisch verlieren sodass man erst noch den neuen wert bekommt.

  3. Stefan Kiesel

    Hallo Marcel,

    nein, so einfach geht das leider nicht, da nicht die JTable den Focus hat, sondern die jeweilige Zelle. Am Ende bläht man den Code mit der FocusListener-Variante nur unnötig auf.

    Grüße
    Stefan

  4. Marcus

    Hallo zusammen,

    nach zwei Jahren noch ein Bemerkung:

    folgender Code geht auch:

    if (table.getCellEditor() != null) {
    table.getCellEditor().cancelCellEditing();
    }

    und hat den gleichen Effekt, wie Eure Lösung.

    Grüße
    Marcus

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.