2017-02-20 10 views
4

Ich habe eine JTable in einem JScrollPane und überschreibe getPreferredScrollableViewportSize, um JScrollPane an eine feste Anzahl von Tabellenzeilen anzupassen, sodass bei Bedarf Scrollbalken angezeigt werden können. Ich habe auch Teile des Codes verwendet, die auf SO gefunden wurden, um die Spalten der Tabelle an ihren Inhalt anzupassen.Richtig überschreiben getPreferredScrollableViewportSize

Das Problem, das ich habe, ist, dass, wenn ich dynamisch eine breitere Zeile der Tabelle hinzufügen, die horizontale JScrollBar nicht angezeigt wird. Ich habe verschiedene Möglichkeiten versucht, die JTable, JViewport und JScrollPane korrekt zu aktualisieren, indem ich revalidate(), oder repaint(), doLayout(), etc., aber ich war nicht erfolgreich.

Natürlich könnte ich pack() -Methode auf JFrame abrufen, aber es würde die gesamte Scroll-Fläche in der Breite wachsen, und die horizontale Bildlaufleiste würde immer noch nicht angezeigt werden.

Was ich vermisse?

Hier gibt es eine MVCE, es ist nur ein hässliches Spielzeug Beispiel, aber es sollte genug sein, um das unerwünschte Verhalten zu replizieren.

Danke für Ihre Hilfe!

Code:

import java.awt.*; 
import java.awt.event.ActionEvent; 
import javax.swing.*; 
import javax.swing.border.EmptyBorder; 
import javax.swing.table.*; 
public class Main 
{ 
    public static void main (String [] a) { 
     SwingUtilities.invokeLater (new Runnable() { 
      public void run() { 
       initGUI(); 
      } 
     }); 
    } 
    private static void initGUI() { 
     final DataTable table = new DataTable(); 
     JPanel container = new JPanel (new BorderLayout (0, 20)); 
     container.add (new JScrollPane (table)); 
     container.add (new JButton (new AbstractAction ("Add wider row") { 
      public void actionPerformed (ActionEvent e) { 
       table.addRow(); 
       // some of many useless attempts ... 
       // table.resizeColumnWidth(); 
       // table.revalidate(); 
      } 
     }), BorderLayout.SOUTH); 
     container.setBorder (new EmptyBorder (10, 10, 10, 10)); 
     JFrame frame = new JFrame ("Test"); 
     frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
     frame.setResizable (false); 
     frame.setContentPane (container); 
     frame.setLocationRelativeTo (null); 
     frame.pack(); 
     frame.setVisible (true); 
    } 
} 
class DataTable extends JTable 
{ 
    private static final int VISIBLE_ROWS = 5; 

    DataTable() { 
     String [][] data = new String [][] { 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"} 
     }; 
     setModel (new DefaultTableModel (data, new String [] {"", ""}) { 
      @Override public boolean isCellEditable (int row, int column) { 
       return false; 
      } 
     }); 
     columnModel.setColumnMargin (20); 
     setBorder (null); 
     setFocusable (false); 
     setRowSelectionAllowed (false); 
     setShowGrid (false); 
     setTableHeader (null); 
     resizeColumnWidth(); 
    } 
    public void addRow() { 
     ((DefaultTableModel) getModel()).addRow (new String [] {"SomeLongerText", "SomeLongerText"}); 
    } 
    private int calculateColumnWidth (int column) { 
     TableColumn tableColumn = columnModel.getColumn (column); 
     int width = 0; 
     for (int row=0; row<getRowCount(); row++) width = Math.max (prepareRenderer (getCellRenderer (row, column), row, column).getPreferredSize().width, width); 
     return width + getIntercellSpacing().width; 
    } 
    @Override public Dimension getPreferredScrollableViewportSize() { 
     int columnsWidth = 0; 
     for (int column=0; column<getColumnCount(); column++) columnsWidth += calculateColumnWidth (column); 
     return new Dimension (columnsWidth, VISIBLE_ROWS * getRowHeight()); 
    } 
    protected void resizeColumnWidth() { 
     for (int column=0; column<getColumnCount(); column++) columnModel.getColumn (column).setPreferredWidth (calculateColumnWidth (column)); 
    } 
} 

EDIT:

Dank @camickr, ich das Problem gelöst, das gewünschte Auto Resize-Modus einstellen und unter Hinweis auf resizeColumnWidth Methode jedes Mal eine Zeile hinzugefügt wird. hatte ich sie schon getrennt versucht, ich kann nicht glauben, dass ich nicht beides :)

Hovewer, verwenden Sie habe ich unter dem aktualisierten Code zu veröffentlichen, jetzt funktioniert es gut:

import java.awt.*; 
import java.awt.event.ActionEvent; 
import javax.swing.*; 
import javax.swing.border.EmptyBorder; 
import javax.swing.table.*; 
public class Main 
{ 
    public static void main (String [] a) { 
     SwingUtilities.invokeLater (new Runnable() { 
      public void run() { 
       initGUI(); 
      } 
     }); 
    } 
    private static void initGUI() { 
     final DataTable table = new DataTable(); 
     JPanel container = new JPanel (new BorderLayout (0, 20)); 
     container.add (new JScrollPane (table)); 
     container.add (new JButton (new AbstractAction ("Add wider row") { 
      public void actionPerformed (ActionEvent e) { 
       table.addRow(); 
      } 
     }), BorderLayout.SOUTH); 
     container.setBorder (new EmptyBorder (10, 10, 10, 10)); 
     JFrame frame = new JFrame ("Test"); 
     frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
     frame.setResizable (false); 
     frame.setContentPane (container); 
     frame.setLocationRelativeTo (null); 
     frame.pack(); 
     frame.setVisible (true); 
    } 
} 
class DataTable extends JTable 
{ 
    private static final int VISIBLE_ROWS = 5; 

    DataTable() { 
     String [][] data = new String [][] { 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"}, 
      {"SomeText", "SomeText"} 
     }; 
     setModel (new DefaultTableModel (data, new String [] {"", ""}) { 
      @Override public boolean isCellEditable (int row, int column) { 
       return false; 
      } 
     }); 
     columnModel.setColumnMargin (20); 
     setAutoResizeMode (AUTO_RESIZE_OFF); 
     setBorder (null); 
     setFocusable (false); 
     setRowSelectionAllowed (false); 
     setShowGrid (false); 
     setTableHeader (null); 
     resizeColumnWidth(); 
    } 
    public void addRow() { 
     ((DefaultTableModel) getModel()).addRow (new String [] {"SomeLongerText", "SomeLongerText"}); 
     resizeColumnWidth(); 
    } 
    private int calculateColumnWidth (int column) { 
     TableColumn tableColumn = columnModel.getColumn (column); 
     int width = 0; 
     for (int row=0; row<getRowCount(); row++) width = Math.max (prepareRenderer (getCellRenderer (row, column), row, column).getPreferredSize().width, width); 
     return width + getIntercellSpacing().width; 
    } 
    @Override public Dimension getPreferredScrollableViewportSize() { 
     int columnsWidth = 0; 
     for (int column=0; column<getColumnCount(); column++) columnsWidth += calculateColumnWidth (column); 
     return new Dimension (columnsWidth, VISIBLE_ROWS * getRowHeight()); 
    } 
    protected void resizeColumnWidth() { 
     for (int column=0; column<getColumnCount(); column++) columnModel.getColumn (column).setPreferredWidth (calculateColumnWidth (column)); 
    } 
} 
+1

Vielen Dank für das Posten eines MCVE mit Ihrer Frage. (+1) und natürlich auch zum camickr. –

Antwort

4

wenn i Fügen Sie der Tabelle dynamisch eine breitere Zeile hinzu, die horizontale JScrollBar wird nicht angezeigt.

Eine horizontale Scrollbalken wird nur auftreten, wenn Sie verwenden:

setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

Alle Spalten werden zu ihrem preffered Größe angezeigt werden. Sie könnten kleiner als das Ansichtsfenster sein. In diesem Fall sehen Sie einen leeren Bereich oder sie könnten größer sein. In diesem Fall sehen Sie die Bildlaufleiste.

Sie müssen Ihre resizeColumnWidth() Methode in Ihrem ActionListener aufrufen, damit die Bildlaufleisten angezeigt werden.

Sie können auch Table Column Adjuster auschecken, die dynamische Spaltengrößenberechnung unterstützen, wenn Daten im TableModel hinzugefügt/geändert werden.

+0

Danke für Ihre Hilfe, das hat mein Problem gelöst. – Ansharja

+0

Ich habe meine Frage mit dem richtigen Code bearbeitet. Es ist schon komisch, dass ich setAutoResizeMode() und resizeColumnWidth bereits separat verwendet habe, ohne sie miteinander zu verbinden. Danke nochmal! – Ansharja