2

私のアプリケーションでは、プログラムの存続期間を通じて動的に入力される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回目に明らかな違いが発生するわけではありません。また、前述したように、これはテーブルの列が縮小するのではなく、拡大した場合にのみ発生します。

私はここで本当に困惑しています。何か案は?

4

2 に答える 2

4

スクロールを正しく機能させるには、おそらく最初の列の優先サイズも指定する必要があります。次の行を追加してみてください:

table.getColumn("Col_1").setPreferredWidth(col_1_width);

Col_1メソッドで計算を処理するブロック内updateTableWidths。投稿されたSSCCEの問題を解決しました。

編集:

のmaxWidthとminWidthに依存関係がありsetPreferredWidthます。以下はのコードですsetPreferredWidth。したがって、順序が重要になる場合があります。

public void setPreferredWidth(int preferredWidth) {
    int old = this.preferredWidth;
    this.preferredWidth = Math.min(Math.max(preferredWidth, minWidth), maxWidth);
    firePropertyChange("preferredWidth", old, this.preferredWidth);
}

また、調査するsetMaxWidthと、優先幅も設定される可能性があることがわかります。

public void setMaxWidth(int maxWidth) {
    int old = this.maxWidth;
    this.maxWidth = Math.max(minWidth, maxWidth);
    if (width > this.maxWidth) {
        setWidth(this.maxWidth);
    }
    if (preferredWidth > this.maxWidth) {
        setPreferredWidth(this.maxWidth);
    }
    firePropertyChange("maxWidth", old, this.maxWidth);
}
于 2013-03-18T21:33:58.407 に答える
3

追加TableColumn#setWidthおよび/またはTableColumn#setPreferredWidth

すなわち

table.getColumn("Col_1").setWidth(col_1_width);
table.getColumn("Col_1").setPreferredWidth(col_1_width);

//...///

table.getColumn("Col_2").setWidth(col_2_width);
table.getColumn("Col_2").setPreferredWidth(col_2_width);
于 2013-03-18T21:34:14.487 に答える