概要

JTableHeaderJPopupMenuを追加してソートします。

サンプルコード

private class TablePopupMenu extends JPopupMenu {
  private final List<SortAction> actions = Arrays.asList(
    new SortAction(SortOrder.ASCENDING),
    new SortAction(SortOrder.DESCENDING));
    // new SortAction(SortOrder.UNSORTED));

  public TablePopupMenu() {
    super();
    for (Action a: actions) {
      add(a);
    }
  }

  @Override public void show(Component c, int x, int y) {
    if (c instanceof JTableHeader) {
      JTableHeader header = (JTableHeader) c;
      JTable table = header.getTable();
      header.setDraggedColumn(null);
      header.repaint();
      table.repaint();
      int i = table.convertColumnIndexToModel(header.columnAtPoint(new Point(x, y)));
      if (i >= 0) {
        actions.forEach(a -> a.setIndex(i));
        super.show(c, x, y);
      }
    }
  }
}

private class SortAction extends AbstractAction {
  private final SortOrder dir;
  private int index = -1;

  public SortAction(SortOrder dir) {
    super(dir.toString());
    this.dir = dir;
  }

  public void setIndex(int index) {
    this.index = index;
  }

  @Override public void actionPerformed(ActionEvent e) {
    table.getRowSorter().setSortKeys(Arrays.asList(
      new RowSorter.SortKey(index, dir)));
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、マウスカーソルの下にあるJTableHeaderカラムをクリック(WindowsLookAndFeel:右クリック)してJPopupMenuを表示し、昇順か降順のJMenuItemを指定してのソートが可能になっています。デフォルトのカラム左クリックによるソートはTableRowSorter#toggleSortOrder(...)をオーバーライドして無効にしています。

  • ソートにJTableHeaderのフォーカスペイントをクリアするために以下のようなPopupMenuListenerを追加
  • 列を右クリックで表示範囲外までドラッグしてからリリースしてポップアップを開くと描画が乱れるので、JPopupMenu#show(...)をオーバーライドしてドラッグ状態の解消、ヘッダ、テーブルの再描画を実行
    • PopupMenuListenerを利用する場合はpopupMenuWillBecomeInvisibleではなくpopupMenuWillBecomeVisibleでも同様の処理を行う
JPopupMenu pop = new TablePopupMenu();
JTableHeader header = table.getTableHeader();
header.setComponentPopupMenu(pop);
pop.addPopupMenuListener(new PopupMenuListener() {
  @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    header.setDraggedColumn(null);
    header.repaint();
    header.getTable().repaint();
  }

  @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    // header.setDraggedColumn(null);
    header.repaint();
    header.getTable().repaint();
  }

  @Override public void popupMenuCanceled(PopupMenuEvent e) {}
});

参考リンク

コメント