2017-02-20 13 views
4

У меня JTable внутри JScrollPane, и я переопределяю getPreferredScrollableViewportSize, чтобы соответствовать JScrollPane фиксированному количеству строк таблицы, позволяя появляться полосы прокрутки, когда это необходимо. Я также использовал части кода, найденные на SO, чтобы изменить размер столбцов таблицы, чтобы они соответствовали их контенту.Правильное переопределение getPreferredScrollableViewportSize

Проблема, с которой я сталкиваюсь, заключается в том, что, когда я динамически добавляю более широкую строку в таблицу, горизонтальный JScrollBar не отображается. Я попытался по-разному заставить JTable, JViewport и JScrollPane правильно обновлять, вызывая revalidate() или repaint(), doLayout() и т. Д., Но мне это не удалось.

Конечно, я могу вспомнить метод pack() на JFrame, но это приведет к увеличению ширины полосы прокрутки, а горизонтальная полоса прокрутки все равно не появится.

Что мне не хватает?

Здесь есть 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)); 
    } 
} 

EDIT:

Благодаря @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), а также, конечно, камикр. –

ответ

4

, когда я динамически добавить более широкую строку в таблицу, горизонтальный JScrollBar не отображается.

горизонтальная полоса прокрутки будет происходить только при использовании:

setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

Все столбцы будут отображаться на их преимущественного размера. Они могут быть меньше, чем область просмотра, и в этом случае вы увидите пустое пространство, или они могут быть больше, и в этом случае вы увидите полосу прокрутки.

Вам необходимо будет вызвать ваш метод resizeColumnWidth() в вашем ActionListener, чтобы появлялись полосы прокрутки.

Вы также можете проверить Table Column Adjuster, которые поддерживают вычисление размера динамической колонки, поскольку данные добавляются/изменяются в TableModel.

+0

Спасибо за вашу помощь, которая решила мою проблему. – Ansharja

+0

Я отредактировал мой вопрос с правильным кодом. Очень смешно, что я уже использовал setAutoResizeMode() и resizeColumnWidth отдельно, не помещая их togheter. Еще раз спасибо! – Ansharja