• category: swing folder: FixedColumnTableSorting title: JTableの列固定とソート tags: [JTable, TableRowSorter, ChangeListener, JScrollPane, JViewport] author: aterai pubdate: 2008-11-10T14:26:25+09:00 description: 列固定したJTableで、JDK 6で導入されたTableRowSorterを使った行ソートを行います。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTMzes1hqI/AAAAAAAAAZw/-m-PZSFzYAk/s800/FixedColumnTableSorting.png

概要

列固定したJTableで、JDK 6で導入されたTableRowSorterを使った行ソートを行います。

サンプルコード

fixedTable = new JTable(model);
#spandel
table      = new JTable(model);
#spanend
#spanadd
table = new JTable(model);
#spanend
fixedTable.setSelectionModel(table.getSelectionModel());
fixedTable.setUpdateSelectionOnSort(false);
#spandel
//table.setUpdateSelectionOnSort(true);
#spanend
#spanadd
// table.setUpdateSelectionOnSort(true);
#spanend

for (int i = model.getColumnCount() - 1; i >= 0; i--) {
  if (i < 2) {
    table.removeColumn(table.getColumnModel().getColumn(i));
    fixedTable.getColumnModel().getColumn(i).setResizable(false);
  } else {
    fixedTable.removeColumn(fixedTable.getColumnModel().getColumn(i));
  }
}

fixedTable.setRowSorter(sorter);
fixedTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
fixedTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

table.setRowSorter(sorter);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

#spandel
final JScrollPane scroll = new JScrollPane(table);
#spanend
#spanadd
JScrollPane scroll = new JScrollPane(table);
#spanend
JViewport viewport = new JViewport();
viewport.setView(fixedTable);
viewport.setPreferredSize(fixedTable.getPreferredSize());
scroll.setRowHeader(viewport);
#spandel
//scroll.setRowHeaderView(fixedTable);
#spanend
#spandel
//fixedTable.setPreferredScrollableViewportSize(fixedTable.getPreferredSize());
#spanend
#spanadd
// scroll.setRowHeaderView(fixedTable);
#spanend
#spanadd
// fixedTable.setPreferredScrollableViewportSize(fixedTable.getPreferredSize());
#spanend
scroll.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
scroll.getViewport().setBackground(Color.WHITE);
viewport.setBackground(Color.WHITE);
#spandel
//<blockquote cite="https://tips4java.wordpress.com/2008/11/05/fixed-column-table/">
#spanend
#spandel
//@auther Rob Camick
#spanend
#spandel
//@title Fixed Column Table ≪ Java Tips Weblog
#spanend
#spanadd
// <blockquote cite="https://tips4java.wordpress.com/2008/11/05/fixed-column-table/">
#spanend
#spanadd
// @auther Rob Camick
#spanend
#spanadd
// @title Fixed Column Table ≪ Java Tips Weblog
#spanend
scroll.getRowHeader().addChangeListener(new ChangeListener() {
  @Override public void stateChanged(ChangeEvent e) {
    JViewport viewport = (JViewport) e.getSource();
    scroll.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
  }
});
#spandel
//</blockquote>
#spanend
#spanadd
// </blockquote>
#spanend
add(scroll);
View in GitHub: Java, Kotlin

解説

左の固定テーブル(fixedTable)と、右のテーブル(table)に同じRowSorterを設定することで、列固定表でもソートできるようにしています。 ただし、上記のサンプルでは、ソート中に行の追加を行うと例外が発生するので、追加の前にsorter.setSortKeys(null);SortKeysをクリアしています。
  • 左の列固定された表(fixedTable)と右の表(table)に同じRowSorterを設定することで、列固定表でもソート可能に設定
  • ソート中に行の追加を行うと例外が発生する
    • 上記のサンプルでは以下のように追加前にsorter.setSortKeys(null)SortKeysをクリアして回避
      add(new JButton(new AbstractAction("add") {
        @Override public void actionPerformed(ActionEvent e) {
          //List<? extends RowSorter.SortKey> keys = sorter.getSortKeys();
          // List<? extends RowSorter.SortKey> keys = sorter.getSortKeys();
          sorter.setSortKeys(null);
          for (int i = 0; i < 100; i++) {
            model.addRow(new Object[] {i, i + 1, "A" + i, "B" + i});
          }
          //sorter.setSortKeys(keys);
          // sorter.setSortKeys(keys);
        }
      }), BorderLayout.SOUTH);
      

行を追加したとき、うまく描画されない場合があるので、以下のようなJPanelをラッパーとして使用しています。
  • 行を追加したとき描画が乱れる場合があるので、以下のようなJPanelをラッパーとして使用
  • 以下を取り違えていたため、描画がおかしくなっていた
    • JScrollPane#setRowHeaderView(Component)
    • JScrollPane#setRowHeader(JViewport)

固定列でキーボードなどによるスクロールに対応するために以下のようなChangeListenerを追加しています。
scroll.getRowHeader().addChangeListener(new ChangeListener() {
  @Override public void stateChanged(ChangeEvent e) {
    JViewport viewport = (JViewport) e.getSource();
    scroll.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
  }
});

参考リンク

コメント