1

を入れてJTable、次のJScrollPaneようにします。

  • 水平方向および垂直方向にスクロール可能(親コンテナよりも大きくなるコンテンツがある場合のみ)
  • 必要に応じて、親コンテナを埋めるために自動的に拡張します(両方向)
  • 必要な場合にのみ、どちらかまたは両方のスクロールバーを使用してください

JListところで、このように動作します。しかし、すべての目標を同時に達成する簡単な方法は見つかりませんでしたJTable。最初の方法を実行する簡単な方法は、自動サイズ変更を無効にすることですが、これにより2番目のサイズが発生しなくなります。コンポーネントリスナーをの親コンテナに追加する非常にハッキーなソリューションを考え出しました。JScrollPaneそのコンテナのサイズが変更されると、テーブルのサイズが変更されます。ただし、サイズ変更方法にいくつかの「ファッジファクター」(4xコメントを参照)を追加する必要がありました。これは、固有の不正確さのために、高さ/幅のチェックを小さなピクセル量で変更します。これらのファッジファクターがないと、スクロールバーが表示されるのが早すぎるか(必要になる前に)、スクロールバーが存在していても長いテーブルセルの最後が途切れてしまいます。これらのハッキーなファッジファクターの最悪の部分は、GUIのルックアンドフィールを変更すると、ソリューション全体が非常にきれいに機能しなくなることです(つまり、ファッジファクターを変更する必要があります)。これは明らかに理想からはほど遠いです。

これを達成するためのよりクリーンな方法が必要です。誰か助けてもらえますか?添付のコードを実行し、フレーム全体のサイズをドラッグして、テーブルの更新を確認します。このコードは、選択したファッジファクターを使用してWindows 7マシンで機能するように見える金属製のルックアンドフィールを使用していますが、別のOSでそれほどきれいに機能しなくても驚かないでしょう。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class JTableScrollTest {

    private JFrame frame;
    private JPanel panel;
    private DefaultTableModel tableModel;
    private JTable table;
    private JScrollPane scrollPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
        } catch (Throwable e) {
            e.printStackTrace();
        }

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTableScrollTest window = new JTableScrollTest();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public JTableScrollTest() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        panel = new JPanel();
        frame.getContentPane().add(panel, BorderLayout.CENTER);
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        scrollPane = new JScrollPane();
        panel.add(scrollPane);

        tableModel = new DefaultTableModel(new Object[]{"Stuff"},0);
        tableModel.addRow(new Object[]{"reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally long string"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"a"});
        tableModel.addRow(new Object[]{"LAST ITEM"});
        table = new JTable(tableModel);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        scrollPane.setViewportView(table);

        resizeTable();
        panel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent evt) {
                resizeTable();
            }
        });
    }

    public void resizeTable() {
        int width = 0;
        int height = 0;
        for (int row = 0; row < table.getRowCount(); row++) {
            TableCellRenderer renderer = table.getCellRenderer(row, 0);
            Component comp = table.prepareRenderer(renderer, row, 0);
            width = Math.max (comp.getPreferredSize().width, width);
            height += comp.getPreferredSize().height;
        }
        if (width > panel.getWidth() - 2) { // fudge factor
            width += 4; // fudge factor
            scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        } else {
            width = panel.getWidth();
            scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        }
        if (height > panel.getHeight() + 4) { // fudge factor
            height -= 26; // fudge factor
            scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        } else {
            height = panel.getHeight();
            scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
        }
        table.setPreferredSize(new Dimension(width, height));
    }
}
4

1 に答える 1

2

私も同じ問題を抱えていました。この表では、スクロールバーを表示するのではなく、列を大きくしたり小さくしたりしています。試行錯誤の末、私が思いついたハックは、ComponentListenerあなたがに付けたものScrollPaneです。

秘訣は、スクロールペインがテーブルの推奨サイズよりも小さくなったら、テーブルの自動サイズ変更をオフにすることです。テーブルの優先サイズを直接設定しないでください。自動的に計算されるようにそれを放っておいてください。特定の列を大きくしたり小さくしたりする必要がある場合は、列モデルを使用して幅を設定します(例table.getColumnModel().getColumn(0).setMaxWidth(25))。

このクラスにはTableModelListener、列がテーブルに追加されたときに同じロジックを実行する別のクラスも含まれています。

public final class ScrollingTableFix implements ComponentListener {
  private final JTable table;

  public ScrollingTableFix(JTable table, JScrollPane scrollPane) {
    assert table != null;

    this.table = table;

    table.getModel().addTableModelListener(new ColumnAddFix(table, scrollPane));
  }

  public void componentHidden(final ComponentEvent event) {}

  public void componentMoved(final ComponentEvent event) {}

  public void componentResized(final ComponentEvent event) {
    // turn off resize and let the scroll bar appear once the component is smaller than the table
    if (event.getComponent().getWidth() < table.getPreferredSize().getWidth()) {
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    }
    // otherwise resize new columns in the table
    else {
        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
    }
  }

  public void componentShown(final ComponentEvent event) {}

  // similar behavior is needed when columns are added to the table
  private static final class ColumnAddFix implements TableModelListener {
    private final JTable table;
    private final JScrollPane scrollPane;

    ColumnAddFix(JTable table, JScrollPane scrollPane) {
      this.table = table;
      this.scrollPane = scrollPane;
     }

    @Override
    public void tableChanged(TableModelEvent e) {
      if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
        if (scrollPane.getViewport().getWidth() < table.getPreferredSize().getWidth()) {
          table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        }
        else {
          table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        }
      }
     }
   }
}

これを使用するには、次のようにすべてを配線するだけです。

JTable table = new JTable();
JScrollPane scroller = new JScrollPane(table);
scroller.addComponentListener(new ScrollingTableFix(table, scroller));
于 2013-01-18T00:23:30.933 に答える