JTable erst nach Änderung der Spaltenbreite neu zeichnen

Status
Nicht offen für weitere Antworten.

tomse

Mitglied
Hallo,

ich habe eine JTable der ich für einige Spalten ein JTextPane als cell renderer zugewiesen habe, um formatierten bzw. mehrzeiligen Text anzuzeigen.
Damit das ganze funktioniert, wird beim neuzeichnen (Aufruf von TableCellRenderer.getTableCellRendererComponent(...)) die Höhe der Zeile berechnet, in der sich die neu zu zeichnende Zelle befindet. Die Höhe der einzelnen Zelle (mit JTextPane renderer) wird dabei über die getPreferredSize().height eines separaten JTextPanes berechnet.

Und jetzt zur eigentlichen Frage:
Beim Ändern der Spaltenbreite durch den User kann man bei langsameren Systemen zugucken, wie die Tabelle neu gezeichnet wird. Gibt es für JTable irgendeine Option um das neuberechnen solange herraus zu zögern, bis die Maustaste wieder losgelassen wurde?
 

tomse

Mitglied
Genau. In getTableCellRendererComponent laufe ich über alle Spalten in der zu aktualisierenden Zeile und bilde das Maximum der Zeilenhöhe und setze sie mittels table.setRowHeight.

So wie es aussieht, ist die seitaufwendige Aktion das Formatieren des Textes um die Höhe des JTextPanes zu berechnen.
Da sich beim Ändern der Tabellengrösse der Inhalt ja nich ändert, wäre mein Problem auch zu lösen, wenn ich an den bereits formatierten Text (Document) der Zellen wieder rankommen würde. Zusätzlich bräuchte ich natürlich noch die Information, warum die Zelle neu berechnet werden soll, also inhaltliche Änderung oder nur resize...
 
Zuletzt bearbeitet:

Michael...

Top Contributor
ein setzen der Zeilenhöhe in der Methode bewirkt ein repaint der Tabelle, das bewirkt wiederum einen Aufruf der getTableCellRendererComponent() Methoden der Renderer usw.
Kurzum damit wird eine Endlosschleife ausgelöst
Das setzen der Zeilenhöhe sollte daher ausserhalb der Renderermethode implementiert werden.
 

tomse

Mitglied
Ich setze die Zeilenhöhe nur neu, wenn sie sich geändert hat.
Aber versuchsweise hab ich die Code-Zeile (setzen der Höhe) mal auskommentiert um zu sehen, ob was zuoft gemacht wird, aber mit und ohne dem Neusetzen der Zeilenhöhe wird der TableCellRenderer genausooft gerufen.
Das mit der (möglichen) Endlosschleife kann ich also so nicht nachvollziehen...
 

Ebenius

Top Contributor
Das ist ganz schön ekelig. Ich würde dazu von der JTable ableiten, doLayout() überschreiben und dort die Berechnung durchführen. Außerdem muss die Tabelle ihre eigene Zeilenhöhe überprüfen, wenn sich die Daten ändern. Sowas in etwa:

Java:
    final JTable table = new JTable(2, 2) {

      /**
       * Adjusts the row height. Uses the maximum preferred height of all
       * cells rendered.
       * <p>
       * TODO: Implement the mechanism to request renderer's preferred cell
       * height with fixed width given.
       */
      protected void adjustAutoRowHeight() {
        final int rowCount = getRowCount();
        final int columnCount = getColumnCount();
        int newRowHeight = 25;
        for (int row = 0; row < rowCount; row++) {
          for (int column = 0; column < columnCount; column++) {
            final Component rendererComponent =
                  prepareRenderer(getCellRenderer(row, column), row, column);
            // adjust maxRowHeight based on renderer content
          }
        }

        final int oldRowHeight = getRowHeight();
        setRowHeight(newRowHeight);
        if (oldRowHeight != newRowHeight && EventQueue.isDispatchThread()) {
          // If the method is called within a layout cycle, we need to revalidate again :-(
          SwingUtilities.invokeLater(new Runnable() {

            public void run() {
              resizeAndRepaint();
            }
          });
        }
      }

      @Override
      public void doLayout() {
        super.doLayout();
        final JTableHeader tableHeader = getTableHeader();
        TableColumn resizingColumn =
              tableHeader != null ? tableHeader.getResizingColumn() : null;
        TableColumn draggedColumn =
              tableHeader != null ? tableHeader.getDraggedColumn() : null;

        if (resizingColumn == null && draggedColumn) {
          adjustAutoRowHeight();
        }
      }

      @Override
      public void tableChanged(TableModelEvent e) {
        super.tableChanged(e);
        if (e != null
              && e.getFirstRow() != TableModelEvent.HEADER_ROW
              && (e.getType() != TableModelEvent.UPDATE || e.getLastRow() != Integer.MAX_VALUE)) {
          // in all other cases, super implementation calls resizeAndRepaint()
          // which triggers doLayout
          adjustAutoRowHeight();
        }
      }
    };

Allerdings sollte das das Problem noch nicht ganz lösen. Der TableHeader sagt einem leider nicht Bescheid, wenn man die zu verschiebende Spalte los lässt. Dazu kann man den TableHeader erweitern:

Java:
    final JTableHeader tweakingTableHeader = new JTableHeader(table.getColumnModel()) {

      private static final long serialVersionUID = 1L;

      @Override
      public void setResizingColumn(TableColumn aColumn) {
        super.setResizingColumn(aColumn);
        final JTable table = getTable();
        if (aColumn == null && table != null) {
          table.revalidate();
        }
      }
    };
    table.setTableHeader(tweakingTableHeader);

Wenn der TableCellRenderer auf Grund der Komplexität trotzdem noch zu langsam ist, dann kann man dort auch noch tricksen, indem man einen anderen Zelleninhalt darstellt, während eine Spalte verschoben/vergrößert/verkleinert wird:

Java:
  private static class TweakingCellRenderer extends DefaultTableCellRenderer {

    private static final long serialVersionUID = 1L;

    private final TableCellRenderer slowRenderer;

    TweakingCellRenderer(TableCellRenderer slowRenderer) {
      this.slowRenderer = slowRenderer;
    }

    @Override
    public Component getTableCellRendererComponent(
          JTable table,
          Object value,
          boolean isSelected,
          boolean hasFocus,
          int row,
          int column) {
      final JTableHeader header = table.getTableHeader();
      if (header != null && header.getResizingColumn() != null) {
        value = "Resizing...";
        setBackground(Color.YELLOW);
      } else if (header != null && header.getDraggedColumn() != null) {
        value = "Moving...";
        setBackground(Color.YELLOW);
      } else {
        return slowRenderer.getTableCellRendererComponent(table, value,
              isSelected, hasFocus, row, column);
      }

      return super.getTableCellRendererComponent(table, value, isSelected,
            hasFocus, row, column);
    }
  }
Java:
    final TableCellRenderer tweakingRenderer =
          new TweakingCellRenderer(new DefaultTableCellRenderer());
    table.setDefaultRenderer(Object.class, theSlowAndComplexRenderer);
Ich hoffe, das hilft weiter.

Kurzum damit wird eine Endlosschleife ausgelöst
Nö. Dadurch gibt's nur eine Endlosschleife, wenn sich die Zeilenhöhe jedes mal ändert. [c]setRowHeight(int)[/c] tut nix, wenn sich die Zeilenhöhe nicht verändert. Das ändert aber nix daran, dass der TableCellRenderer die Tabelle nicht verändern sollte, weil ihm das einfach nicht zusteht. :)

Ebenius
 
Zuletzt bearbeitet:

tomse

Mitglied
Vielen Dank erstmal euch beiden!

@Ebenius
Ich hab mal deinen code dahingehend modifizert, dass ich mich beim ersten Aufruf mit einem MouseListener in den TableHeader einklinke, und beim loslassen der MausTaste nochmal das Neuzeichnen der Tabelle anstosse (allerdings mit fireTableDataChanged(); ein einfaches revalidate() funktioniert bei mir nicht - hab noch nicht weiter nach der Ursache gesucht)

Ansonsten setze ich den Text einfach erstmal so, wie er kommt, der wird dann während des resizes ggf. erstmal abgeschnitten und die neue Höhe wird nach dem loslassen der Maustaste berechnet.

Ist vielleicht noch nicht ganz optimal, aber auf jeden Fall schon mal ein brauchbarer Ansatz...

Vielen Dank!

Und hier nochmal wie's jetzt ungefähr aussieht (bischen abgespeckt):
Java:
private static class MyCellRenderer extends JTextPane implements TableCellRenderer {
  private boolean firstCall = true;
 
    @Override
    public Component getTableCellRendererComponent(
          JTable table,
          Object value,
          boolean isSelected,
          boolean hasFocus,
          int row,
          int column) {

      final JTableHeader header = table.getTableHeader();
      if (firstCall) {
        final JTable t = table;
        header.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseReleased(MouseEvent arg0) {
            AbstractTableModel d = (AbstractTableModel)t.getModel();
            d.fireTableDataChanged();
        }
      });
      firstCall = false;
    }

    setText((String)value);

      if (header != null && header.getResizingColumn() != null) {
        setBackground(Color.YELLOW);
      } else if (header != null && header.getDraggedColumn() != null) {
        setBackground(Color.YELLOW);
      } else {
        // calculate row height and set new height if necessary
      }
 
      return this;
    }
  }
 

Ebenius

Top Contributor
Ne, da haste irgendwie was falsch verstanden. Auf keinen Fall sollte ein TableCellRenderer Listener eines JTableHeader sein. Das ist Schweinkram, sorry. ;-)

Ebenius
 

tomse

Mitglied
[...] Auf keinen Fall sollte ein TableCellRenderer Listener eines JTableHeader sein. Das ist Schweinkram, sorry. ;-)
Die Aussage ist erstmal sehr pauschal - kannst du das irgendwie konkretisieren?

Den Vorteil, den ich an der Lösung mit dem MouseListener sehe ist der, dass der TableCellRenderer als eigenständige Komponente benutzt werden kann. Bei deiner Lösung sind beide Teile getrennt, also wenn man den TableCellRenderer ohne den modifizerten Header benutzt funktioniert das Ganze nicht mehr. Ausserdem erscheint mir das mit dem Listener simpler zu sein (keep it simple...) - oder nicht?
 

Ebenius

Top Contributor
Ein CellRenderer hat eine Aufgabe: Er initialisiert einer Komponente mit der eine Zelle gezeichnet werden kann. Renderer sind immer passiv. Sie steuern niemals.

Den Vorteil, den ich an der Lösung mit dem MouseListener sehe ist der, dass der TableCellRenderer als eigenständige Komponente benutzt werden kann. Bei deiner Lösung sind beide Teile getrennt, also wenn man den TableCellRenderer ohne den modifizerten Header benutzt funktioniert das Ganze nicht mehr. Ausserdem erscheint mir das mit dem Listener simpler zu sein (keep it simple...) - oder nicht?
Abgesehen davon, dass dieser CellRenderer Dinge tut die er nicht tun sollte (Verhalten der Tabelle steuern, Modell-Ereignisse fälschen), folgende Fragen: Wer entfernt den CellRenderer als MouseListener vom JTableHeader, wenn ich den Header austausche? Wer fügt den CellRenderer wieder als MouseListener zum neuen JTableHeader hinzu? Wer entfernt den CellRenderer als MouseListener vom JTableHeader, wenn ich den Renderer nicht mehr benötige (und der Garbage Collector in aufräumen könnte, wenn er nicht am JTableHeader dranhinge)? Wie sorgt der CellRenderer dafür, dass er in einer zweiten Tabelleninstanz ebenso funktioniert ([c]first[/c] wird ja nur einmal auf [c]false[/c] gesetzt)? Eben.

Ebenius
 

tomse

Mitglied
Abgesehen davon, dass dieser CellRenderer Dinge tut die er nicht tun sollte (Verhalten der Tabelle steuern, Modell-Ereignisse fälschen), folgende Fragen: Wer entfernt den CellRenderer als MouseListener vom JTableHeader, wenn ich den Header austausche? Wer fügt den CellRenderer [...]
OK, alles keine unlösbaren Aufgaben, aber ich geb dir Recht, die Lösung ist nicht ganz rund und das "single responsibility" Argument überzeugt mich dann doch...
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
S JComboBox in JTable wird erst nach klick angezeigt AWT, Swing, JavaFX & SWT 2
S [JTable] Editor erst nach Doppelklick AWT, Swing, JavaFX & SWT 5
V Swing Custom JToggleButton in JTable - Click-Event geht erst beim zweiten Mal AWT, Swing, JavaFX & SWT 7
T JSpinner in JTable: Problem beim Auslesen, funktioniert erst beim Zellwechsel AWT, Swing, JavaFX & SWT 7
X JTable "geht" erst beim 2.Klick AWT, Swing, JavaFX & SWT 2
J JTable Änderung erst beim Zeilenwechsel AWT, Swing, JavaFX & SWT 5
J Drag und drop aus einer JTable - bitte um Unterstützung AWT, Swing, JavaFX & SWT 2
S HPRO und UPRO gemeinsame JTABLE gemeinsamer RENDERER ? AWT, Swing, JavaFX & SWT 1
F Swing JTable - MultiHeader inkl. Eingabemöglichkeit AWT, Swing, JavaFX & SWT 1
S JTable - Feldinhalte anzeigen AWT, Swing, JavaFX & SWT 15
D Swing JTable Spaltenbreite AWT, Swing, JavaFX & SWT 1
W Gibt es einen "automatischen Listener" in Swing oder JTable oder der ATM-Klasse? AWT, Swing, JavaFX & SWT 14
G jTable - getSelectedRow() AWT, Swing, JavaFX & SWT 3
I JTable mit einem Button zu einer Detail Seite springen AWT, Swing, JavaFX & SWT 4
P JTable Listener für die Änderung einzelner Zellen oder Rows AWT, Swing, JavaFX & SWT 2
D Tastaturabfragen CTRL+t, CTRL+E bei eine JTable, bestehend aus JTextAteas AWT, Swing, JavaFX & SWT 4
P Checkboxes in JTable nicht editable AWT, Swing, JavaFX & SWT 9
F Best-Practise: JTable Text in Zelle zu groß AWT, Swing, JavaFX & SWT 2
izoards JTable in CSV File schreiben... AWT, Swing, JavaFX & SWT 23
Kohl Jedes Objekt einer JTable um ein Zeichen verkürzen AWT, Swing, JavaFX & SWT 7
I JTable, DefaultTableModel, zwei Zahlen multiplizieren. AWT, Swing, JavaFX & SWT 26
M JTABLE / wie oft wurde gewürfelt. AWT, Swing, JavaFX & SWT 1
F JTable vergrößern AWT, Swing, JavaFX & SWT 2
H JTable: Diverse NullPointer-Exceptions zur Laufzeit AWT, Swing, JavaFX & SWT 3
J Swing Werte des JTable werden nicht angezeigt AWT, Swing, JavaFX & SWT 9
T Swing JTable cellRenderer mit jpg Hintergrundfarbe lässt sich nicht ändern. AWT, Swing, JavaFX & SWT 1
HoT Einzelne Zelle in JTable Rahmen unten setzen AWT, Swing, JavaFX & SWT 24
B JTable Zellen zusammenfügen AWT, Swing, JavaFX & SWT 3
M Swing Cell Renderer für Zeilenumbruch in JTable AWT, Swing, JavaFX & SWT 0
H JTable im JSplitPane darstellen AWT, Swing, JavaFX & SWT 2
MadMax2506 Swing JTable lädt sehr lange AWT, Swing, JavaFX & SWT 1
D Zeilenumbruch in einer JTable AWT, Swing, JavaFX & SWT 9
R Swing JTable und Spaltenausrichtung AWT, Swing, JavaFX & SWT 8
G JTable füllen AWT, Swing, JavaFX & SWT 1
H JTable TableCellEditor-Problem AWT, Swing, JavaFX & SWT 0
W Swing JTable Zeilenumbruch innerhalb einer Zelle AWT, Swing, JavaFX & SWT 3
J Datensatz in jTable ausgeben AWT, Swing, JavaFX & SWT 3
M Swing Automatischer Editorstart in JTable-Zelle AWT, Swing, JavaFX & SWT 5
ralfb1105 Swing JTable aktualisieren AWT, Swing, JavaFX & SWT 5
adiko01 JTable: Nur markierte Zeilen aus der Tabelle in CSV exportiern AWT, Swing, JavaFX & SWT 9
M JTable.setDefaultRenderer(...) greift nicht AWT, Swing, JavaFX & SWT 0
J JTable: Eingabe in Tabellenzelle korrigieren AWT, Swing, JavaFX & SWT 4
T Problem mit JTable Sortierung AWT, Swing, JavaFX & SWT 2
D JTable nach INSERT aktualisieren /refreshen AWT, Swing, JavaFX & SWT 1
D MySQL Daten in JTable anzeigen AWT, Swing, JavaFX & SWT 2
H Swing Jtable extra spalte AWT, Swing, JavaFX & SWT 6
S Swing Rechteck über JTable zeichnen (per MouseListener) AWT, Swing, JavaFX & SWT 1
S Swing Mal wieder JTable Ansicht aktualisieren AWT, Swing, JavaFX & SWT 10
A JTable mit Daten füllen AWT, Swing, JavaFX & SWT 1
VfL_Freak Swing Einzelne Zeile in jTable selektieren klappt nicht AWT, Swing, JavaFX & SWT 7
N AWT jTable CellRenderer AWT, Swing, JavaFX & SWT 6
T Swing JTable valueChanged datensatz löschen AWT, Swing, JavaFX & SWT 1
0 Swing JTable aus anderer Klasse updaten AWT, Swing, JavaFX & SWT 5
S Jtable defaultRenderer wohin damit ? AWT, Swing, JavaFX & SWT 23
T Swing JTable / FocusListener AWT, Swing, JavaFX & SWT 0
it_is_all Warum wird die JTable im JDialog nicht angezeigt? AWT, Swing, JavaFX & SWT 1
L Swing JTable im Panel darstellen AWT, Swing, JavaFX & SWT 8
T Swing Double Click bei Buttons in JTable AWT, Swing, JavaFX & SWT 9
J addRow bei JTable AWT, Swing, JavaFX & SWT 6
M Jtable gibt -1 wert bei selectedRow und Column AWT, Swing, JavaFX & SWT 3
Meeresgott Swing JTable AWT, Swing, JavaFX & SWT 4
J JTable Selection Listener funktioniert nicht AWT, Swing, JavaFX & SWT 4
C Swing Daten in JTable wiedergeben per TableModel und MVC Pattern AWT, Swing, JavaFX & SWT 16
Z Swing Drag&Drop zwischen JTable und JTree AWT, Swing, JavaFX & SWT 4
Thallius JTable dynamisch Spaltenanzahl verändern AWT, Swing, JavaFX & SWT 2
Thallius JTable dynamisch laden? AWT, Swing, JavaFX & SWT 2
B Swing JTable sortieren AWT, Swing, JavaFX & SWT 2
T Swing JTable auslesen und befüllen AWT, Swing, JavaFX & SWT 8
B JTable wird nicht angezeigt AWT, Swing, JavaFX & SWT 1
J JTable und Suchlogik AWT, Swing, JavaFX & SWT 4
Viktim Swing JTable mit Tab verlassen AWT, Swing, JavaFX & SWT 1
F Swing Spaltenbreite einer Column eines JTable auslesen AWT, Swing, JavaFX & SWT 5
Viktim Swing JTable Mit Tab druch Zeilen Wechseln AWT, Swing, JavaFX & SWT 5
Thallius Warum refrehsed mein JTable nicht? AWT, Swing, JavaFX & SWT 5
Ghostman1711 Hinzufügen ausgewählter Dateinen des Filechoosers zu einem JTable AWT, Swing, JavaFX & SWT 9
S Swing JTable - Einzelne Rows einfärben AWT, Swing, JavaFX & SWT 11
M Wert einer Zelle aus JTable ziehen AWT, Swing, JavaFX & SWT 4
K JTable getValueAt() klappt nicht immer AWT, Swing, JavaFX & SWT 1
K JTable in extra Klasse, Zugriff in einer anderen klasse nicht möglich AWT, Swing, JavaFX & SWT 26
B Swing Tabelle(JTable) filtern swing GUI AWT, Swing, JavaFX & SWT 3
P JTable - bei Eingabe Selektion AWT, Swing, JavaFX & SWT 0
P Fokus auf Zelle in JTable AWT, Swing, JavaFX & SWT 1
S Swing Deselektion in JTable verhindern AWT, Swing, JavaFX & SWT 0
D Problem mit JTable AWT, Swing, JavaFX & SWT 1
N Swing Print JTable mit AbstractTableModel AWT, Swing, JavaFX & SWT 1
Ananaskirsche Swing jTable Reihen zuviel eingefügt AWT, Swing, JavaFX & SWT 12
P im JTable die Schriftfarbe ändern AWT, Swing, JavaFX & SWT 19
T Swing JTable wird nicht angezeigt AWT, Swing, JavaFX & SWT 4
S Dreiecke in bestimmte Zellen einer JTable AWT, Swing, JavaFX & SWT 9
LexeB4F Zelle in JTable gezielt einfärben AWT, Swing, JavaFX & SWT 4
LexeB4F JTable mehrere Zelle selektieren und inhalte Löschen.. Ideen gesucht AWT, Swing, JavaFX & SWT 1
D Swing JTable Renderer Grafikfehler AWT, Swing, JavaFX & SWT 0
K Swing JTable mit ImageIcon und Text in einer Zelle AWT, Swing, JavaFX & SWT 1
M Swing JTable GroupableHeader Background Color AWT, Swing, JavaFX & SWT 4
K Swing JTable updaten AWT, Swing, JavaFX & SWT 9
thet1983 Swing MySQL >> JTable AWT, Swing, JavaFX & SWT 5
J JTable bounds ändern durch resizing des Fensters AWT, Swing, JavaFX & SWT 9
F JTable Zellen-Hintergrund ändern AWT, Swing, JavaFX & SWT 7
O JTable linksbündig drucken (nicht der Zelleninhalt) AWT, Swing, JavaFX & SWT 2
Crazynet xls Datei in JTable AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben