3

ここで以前に議論された問題に遭遇しています: をJScrollPane含む aJTableを取得して、水平スクロールバーを希望どおりに表示します。 HEREは私がフォローしようとした投稿ですが、何らかの理由で私の状況ではうまくいかないようです (列の1つを固定幅に設定したためだと思います.

SSCCE は次のとおりです。

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

@SuppressWarnings("serial")
public class TableScrollTest extends JFrame
{
    public TableScrollTest() {

        DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"},0);
        model.addRow(new Object[]{"short", "blah"});
        model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"});

        JTable table = new JTable(model) {
            public boolean getScrollableTracksViewportWidth() {
                return getPreferredSize().width < getParent().getWidth();
            }
        };        
        table.getColumn("key").setPreferredWidth(60);
        table.getColumn("key").setMinWidth(60);
        table.getColumn("key").setMaxWidth(60);
        table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );

        JScrollPane scrollPane = new JScrollPane( table );
        getContentPane().add( scrollPane );
    }

    public static void main(String[] args) {
        TableScrollTest frame = new TableScrollTest();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setSize(200, 200);
        frame.setResizable(false);
        frame.setVisible(true);
    }
}

つまり、キーと値のペアを表示するための 2 列のテーブルがあります。テーブルを保持するコンテナーは固定幅であり、テーブルの最初の列も固定幅です (すべてのキー名の長さがわかっているため)。2 番目の列には、さまざまな文字列長の値が含まれます。水平スクロールバーは、長すぎて列に割り当てられた幅に収まらない値が存在する場合にのみ表示されます。

ここに画像の説明を入力

上記の 2 番目の値は非常に長いため、スクロールバーが表示されるはずです。ただし、そうではなく、私が試したすべてのことは、常に表示することに成功しただけであり、これは私が望むものではありません...「長い」値が存在する場合にのみ表示したいです。テーブルコンストラクターでオーバーライドされているgetScrollableTracksViewportWidth()メソッドは、テーブルの優先幅が何であるかをチェックしているようです...そのため、どういうわけか、その2番目の列の内容のみに基づいて、より大きな幅を優先するようにテーブルに指示する必要があります...しかし、私は困惑しています。

何か案は?

4

3 に答える 3

6

これはハッキーなソリューションです

基本的に、すべての行の値に基づいて、すべての列の「優先」幅を計算します。

モデルへの変更だけでなく、親コンテナーへの変更も考慮されます。

完了すると、「優先」幅が使用可能なスペースより大きいか小さいかを確認し、それにtrackViewportWidth応じて変数を設定します。

固定列のチェックを追加できますが (私は気にしませんでした)、プロセスを「わずかに」高速化しますが、テーブルに列と行を追加すると、更新ごとにモデル全体の歩行。

ある種のキャッシュを入れることもできますが、その頃には、固定幅の列を検討しています;)

import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class TableScrollTest extends JFrame {

    public TableScrollTest() {

        DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"}, 0);
        model.addRow(new Object[]{"short", "blah"});
        model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"});

        JTable table = new JTable(model) {
            private boolean trackViewportWidth = false;
            private boolean inited = false;
            private boolean ignoreUpdates = false;

            @Override
            protected void initializeLocalVars() {
                super.initializeLocalVars();
                inited = true;
                updateColumnWidth();
            }

            @Override
            public void addNotify() {
                super.addNotify();
                updateColumnWidth();
                getParent().addComponentListener(new ComponentAdapter() {
                    @Override
                    public void componentResized(ComponentEvent e) {
                        invalidate();
                    }
                });
            }

            @Override
            public void doLayout() {
                super.doLayout();
                if (!ignoreUpdates) {
                    updateColumnWidth();
                }
                ignoreUpdates = false;
            }

            protected void updateColumnWidth() {
                if (getParent() != null) {
                    int width = 0;
                    for (int col = 0; col < getColumnCount(); col++) {
                        int colWidth = 0;
                        for (int row = 0; row < getRowCount(); row++) {
                            int prefWidth = getCellRenderer(row, col).
                                    getTableCellRendererComponent(this, getValueAt(row, col), false, false, row, col).
                                    getPreferredSize().width;
                            colWidth = Math.max(colWidth, prefWidth + getIntercellSpacing().width);
                        }

                        TableColumn tc = getColumnModel().getColumn(convertColumnIndexToModel(col));
                        tc.setPreferredWidth(colWidth);
                        width += colWidth;
                    }

                    Container parent = getParent();
                    if (parent instanceof JViewport) {
                        parent = parent.getParent();
                    }

                    trackViewportWidth = width < parent.getWidth();
                }
            }

            @Override
            public void tableChanged(TableModelEvent e) {
                super.tableChanged(e);
                if (inited) {
                    updateColumnWidth();
                }
            }

            public boolean getScrollableTracksViewportWidth() {
                return trackViewportWidth;
            }

            @Override
            protected TableColumnModel createDefaultColumnModel() {
                TableColumnModel model = super.createDefaultColumnModel();
                model.addColumnModelListener(new TableColumnModelListener() {
                    @Override
                    public void columnAdded(TableColumnModelEvent e) {
                    }

                    @Override
                    public void columnRemoved(TableColumnModelEvent e) {
                    }

                    @Override
                    public void columnMoved(TableColumnModelEvent e) {
                        if (!ignoreUpdates) {
                            ignoreUpdates = true;
                            updateColumnWidth();
                        }
                    }

                    @Override
                    public void columnMarginChanged(ChangeEvent e) {
                        if (!ignoreUpdates) {
                            ignoreUpdates = true;
                            updateColumnWidth();
                        }
                    }

                    @Override
                    public void columnSelectionChanged(ListSelectionEvent e) {
                    }
                });
                return model;
            }
        };
        table.getColumn("key").setPreferredWidth(60);
//        table.getColumn("key").setMinWidth(60);
//        table.getColumn("key").setMaxWidth(60);
//        table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);

        JScrollPane scrollPane = new JScrollPane(table);
        getContentPane().add(scrollPane);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                TableScrollTest frame = new TableScrollTest();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.pack();
                frame.setSize(200, 200);
                frame.setResizable(true);
                frame.setVisible(true);
            }
        });
    }
}
于 2013-02-22T01:34:55.450 に答える
4

私の目標は、セルレンダラーにセルを自動的に長い文字列に合わせさせることです

これはレンダラーの仕事ではありません。列の幅を手動で設定する必要があります。

これを行う 1 つの方法については、 Table Column Adjusterを参照してください。

于 2013-02-22T01:28:25.843 に答える
1

より賢いものが投稿された場​​合、必ずしもこの回答を受け入れるとは限りませんが、これまでに投稿されたコメントとこの投稿に基づいて、私が自分で考え出した解決策を次に示します。唯一の落とし穴は、私が考えていた幅が常に 1 ピクセル以下で短すぎることです (一部のルック アンド フィールでは問題ありませんでした) width += 5。私にはハッキーに感じます。このアプローチに関するコメントを歓迎します。

import java.awt.Component;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

@SuppressWarnings("serial")
public class TableScrollTest extends JFrame {
    public TableScrollTest() {
        DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"},0);
        model.addRow(new Object[]{"short", "blah"});
        model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"});

        JTable table = new JTable(model);        
        table.getColumn("key").setPreferredWidth(60);
        table.getColumn("key").setMinWidth(60);
        table.getColumn("key").setMaxWidth(60);
        table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );

        int width = 0;
        for (int row = 0; row < table.getRowCount(); row++) {
            TableCellRenderer renderer = table.getCellRenderer(row, 1);
            Component comp = table.prepareRenderer(renderer, row, 1);
            width = Math.max (comp.getPreferredSize().width, width);
        }
        width += 5;
        table.getColumn("value").setPreferredWidth(width);
        table.getColumn("value").setMinWidth(width);
        table.getColumn("value").setMaxWidth(width);

        JScrollPane scrollPane = new JScrollPane( table );
        getContentPane().add( scrollPane );
    }

    public static void main(String[] args) {
        TableScrollTest frame = new TableScrollTest();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setSize(200, 200);
        frame.setResizable(false);
        frame.setVisible(true);
    }
}
于 2013-02-22T01:34:54.797 に答える