2017-02-20 52 views
4

我在JScrollPane中有一個JTable,並且我重寫了getPreferredScrollableViewportSize以便將JScrollPane適合固定數量的錶行,從而允許在需要時顯示滾動條。 我還使用SO上的部分代碼來調整表格列的大小以適應其內容。正確重寫getPreferredScrollableViewportSize

我遇到的問題是,當我dinamically向表中添加更寬的行時,水平JScrollBar不顯示。我嘗試了不同的方法來強制JTable,JViewport和JScrollPane正確更新,調用revalidate()或repaint(),doLayout()等,但我沒有成功。

當然,我可以回想起JFrame中的pack()方法,但它會導致整個滾動窗口的寬度增加,並且水平滾動條仍然不會出現。

我失蹤了什麼?

這裏有一個MVCE,它只是一個醜陋的玩具的例子,但它應該足以複製不想要的行爲。

感謝您的幫助!

代碼:

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)); 
    } 
} 

編輯:

感謝@camickr,我解決了這個問題,設置所需的自動調整模式,每加一排一次回顧resizeColumnWidth方法。 我已經分開審訊他們,我不能相信我沒有使用這兩個:)

Hovewer,我發佈更新的代碼下面,現在它工作得很好:

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

感謝您發佈MCVE與您的問題。 (+1),當然也適用於camickr。 –

回答

4

當我dinamically添加更寬的行到表,水平JScrollBar不顯示。

setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

所有列將在他們的優先停留尺寸顯示:當您使用

一個水平滾動條時,纔會發生。它們可能比視口小,在這種情況下,您將看到空白區域,或者它們可能會更大,在這種情況下,您將看到滾動條。

爲了滾動條出現,您需要在ActionListener中調用resizeColumnWidth()方法。

您還可以查看Table Column Adjuster哪些支持動態列大小計算,因爲數據在TableModel中添加/更改。

+0

感謝您的幫助,解決了我的問題。 – Ansharja

+0

我用正確的代碼編輯了我的問題。非常有趣的是,我已經分別使用了setAutoResizeMode()和resizeColumnWidth,而沒有將它們放大。再次感謝你! – Ansharja