私のアプリケーションでは、プログラムの存続期間を通じて動的に入力される2列のテーブルがあります。呼び出されたときに次のことを行うというメソッドupdateTableWidths
があります。
- セルの内容に合わせるために必要な幅の最初の列を作成します
- セルの内容に合わせるために必要な幅と同じ幅の2番目の列を作成します
- テーブル全体がそのコンテナよりも広い場合は、水平スクロールバーを有効にします
- それ以外の場合は、最後の列を伸ばしてコンテナを埋めます
うまく機能しているように見えますが、いくつかの非常に奇妙な理由で、2回呼び出す必要があります(ただし、場合によっては、テーブルの幅が縮小するのではなく拡大する場合のみ)。以下のSSCCEは、私のジレンマを示しています。
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
@SuppressWarnings("serial")
public class TableResizeTest extends JComponent {
private JFrame frame;
private JScrollPane scrollPane;
private DefaultTableModel tableModel;
private JTable table;
private JPanel panel;
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Throwable e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TableResizeTest window = new TableResizeTest();
window.frame.setVisible(true);
window.frame.requestFocusInWindow();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TableResizeTest() {
initialize();
}
private void initialize() {
frame = new JFrame("Test");
frame.setBounds(300, 300, 200, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tableModel = new DefaultTableModel(new Object[]{"Col_1", "Col_2"},0);
table = new JTable(tableModel);
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
table.setAlignmentY(Component.TOP_ALIGNMENT);
table.setAlignmentX(Component.LEFT_ALIGNMENT);
table.setBorder(new EmptyBorder(0, 0, 0, 0));
table.setFillsViewportHeight(true);
table.setTableHeader(null);
table.setEnabled(false);
table.getColumnModel().setColumnMargin(0);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
panel = new JPanel();
frame.getContentPane().add(panel);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JButton btnFillTableShort = new JButton("Fill table short");
btnFillTableShort.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(btnFillTableShort);
JButton btnFillTableLong = new JButton("Fill table long");
btnFillTableLong.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(btnFillTableLong);
JButton btnUpdateTableWidths = new JButton("Update table widths");
btnUpdateTableWidths.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(btnUpdateTableWidths);
btnUpdateTableWidths.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateTableWidths();
}
});
btnFillTableLong.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fillTableLong();
}
});
btnFillTableShort.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fillTableShort();
}
});
scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(200, 100));
scrollPane.setMaximumSize(new Dimension(32767, 100));
frame.getContentPane().add(scrollPane);
scrollPane.setAlignmentY(Component.TOP_ALIGNMENT);
scrollPane.setBorder(new LineBorder(new Color(0, 0, 0)));
frame.pack();
}
public void fillTableShort() {
tableModel.setRowCount(0);
tableModel.addRow(new Object[]{"short", "short"});
}
public void fillTableLong() {
tableModel.setRowCount(0);
tableModel.addRow(new Object[]{"looooooooooooooooooooong", "looooooooooooooooooooong"});
}
public void updateTableWidths() {
int col_1_width = 0;
for (int row = 0; row < table.getRowCount(); row++) {
TableCellRenderer renderer = table.getCellRenderer(row, 0);
Component comp = table.prepareRenderer(renderer, row, 0);
col_1_width = Math.max (comp.getPreferredSize().width, col_1_width);
}
col_1_width += table.getIntercellSpacing().width;
col_1_width += 10;
table.getColumn("Col_1").setMinWidth(col_1_width);
table.getColumn("Col_1").setMaxWidth(col_1_width);
System.out.println("col_1_width was set to " + col_1_width);
int col_2_width = 0;
for (int row = 0; row < table.getRowCount(); row++) {
TableCellRenderer renderer = table.getCellRenderer(row, 1);
Component comp = table.prepareRenderer(renderer, row, 1);
col_2_width = Math.max (comp.getPreferredSize().width, col_2_width);
}
col_2_width += table.getIntercellSpacing().width;
int tableWidth = col_2_width + col_1_width;
if (scrollPane.getVerticalScrollBar().isVisible()) {
tableWidth += scrollPane.getVerticalScrollBar().getWidth();
}
if (tableWidth > scrollPane.getWidth()) {
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
System.out.println("Auto resize was set to AUTO_RESIZE_OFF");
} else {
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
col_2_width = scrollPane.getWidth() + col_1_width;
System.out.println("Auto resize was set to AUTO_RESIZE_LAST COLUMN");
}
table.getColumn("Col_2").setPreferredWidth(col_2_width);
table.getColumn("Col_2").setMinWidth(col_2_width);
System.out.println("col_2_width was set to " + col_2_width + "\n");
}
}
動作を再現するために実行できる一連の手順は次のとおりです。
1)アプリを起動します
2)「テーブルを短く埋める」ボタンをクリックします
3)[テーブル幅の更新]ボタンをクリックします(この場合、ワンクリックで済みます)
4)「テーブルを長く埋める」ボタンをクリックします
5)[テーブル幅の更新]ボタンをクリックします(最初のクリック)
6)[テーブル幅の更新]ボタンをクリックします(2回目のクリック)
2回目のクリック後、正しく表示されます。コンソールに出力するデバッグ情報がいくつかあります。最初のクリックと2回目のクリックの両方で、メソッドはまったく同じことをしているようです。
col_1_width was set to 152
Auto resize was set to AUTO_RESIZE_OFF
col_2_width was set to 142
したがって、最初の実行中に何かが変更された結果として、2回目に明らかな違いが発生するわけではありません。また、前述したように、これはテーブルの列が縮小するのではなく、拡大した場合にのみ発生します。
私はここで本当に困惑しています。何か案は?