У меня 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));
}
}
Благодарим вас за сообщение MCVE с вашим вопросом. (+1), а также, конечно, камикр. –