• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JTableHeaderにJPopupMenuを追加してソート
#navi(../)
#tags(JTable, JTableHeader, JPopupMenu, PopupMenuListener, TableRowSorter)
RIGHT:Posted by &author(aterai); at 2009-12-07
*JTableHeaderにJPopupMenuを追加してソート [#h2e26e10]
``JTableHeader``に``JPopupMenu``を追加してソートします。
---
category: swing
folder: RowSorterPopupMenu
title: JTableHeaderにJPopupMenuを追加してソート
tags: [JTable, JTableHeader, JPopupMenu, PopupMenuListener, TableRowSorter]
author: aterai
pubdate: 2009-12-07T14:24:46+09:00
description: JTableHeaderにJPopupMenuを追加してソートします。
image: https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTSY9WWpNI/AAAAAAAAAis/Z0YqvftAIh8/s800/RowSorterPopupMenu.png
---
* 概要 [#summary]
`JTableHeader`に`JPopupMenu`を追加してソートします。

-&jnlp;
-&jar;
-&zip;
#download(https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTSY9WWpNI/AAAAAAAAAis/Z0YqvftAIh8/s800/RowSorterPopupMenu.png)

//#screenshot
#ref(http://lh6.ggpht.com/_9Z4BYR88imo/TQTSY9WWpNI/AAAAAAAAAis/Z0YqvftAIh8/s800/RowSorterPopupMenu.png)

**サンプルコード [#f95550c3]
* サンプルコード [#sourcecode]
#code(link){{
private class TablePopupMenu extends JPopupMenu {
  private final List<SortAction> actions = Arrays.asList(
    new SortAction(SortOrder.ASCENDING),
    new SortAction(SortOrder.DESCENDING));
    //new SortAction(SortOrder.UNSORTED));
    // new SortAction(SortOrder.UNSORTED));

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

  @Override public void show(Component c, int x, int y) {
    JTableHeader h = (JTableHeader)c;
    int i = h.columnAtPoint(new Point(x, y));
    i = h.getTable().convertColumnIndexToModel(i);
    for(SortAction a:actions) a.setIndex(i);
    super.show(c, x, 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 class SortAction extends AbstractAction {
  private final SortOrder dir;
  private int index = -1;

  public SortAction(SortOrder dir) {
    super(dir.toString());
    this.dir = dir;
  }
  private int index = -1;

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

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

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

-左クリックではソートしない
- %%ソートに`JTableHeader`のフォーカスペイントをクリアするために以下のような`PopupMenuListener`を追加%%
- 列を右クリックで表示範囲外までドラッグしてからリリースしてポップアップを開くと描画が乱れるので、`JPopupMenu#show(...)`をオーバーライドしてドラッグ状態の解消、ヘッダ、テーブルの再描画を実行
-- `PopupMenuListener`を利用する場合は`popupMenuWillBecomeInvisible`ではなく`popupMenuWillBecomeVisible`でも同様の処理を行う

----
ソートしたあとで、``JTableHeader``のフォーカスペイントをクリアするために以下のような``PopupMenuListener``を追加しています。

#code{{
JPopupMenu pop = new TablePopupMenu();
final JTableHeader header = table.getTableHeader();
JTableHeader header = table.getTableHeader();
header.setComponentPopupMenu(pop);
pop.addPopupMenuListener(new PopupMenuListener() {
  @Override public void popupMenuCanceled(PopupMenuEvent e) {}
  @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    //System.out.println("popupMenuWillBecomeInvisible");
  @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    header.setDraggedColumn(null);
    //header.setResizingColumn(null);
    //header.setDraggedDistance(0);
    header.repaint();
    header.getTable().repaint();
  }
  @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}

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

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

//**参考リンク
**コメント [#pda540a5]
* 参考リンク [#reference]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/DefaultRowSorter.html#toggleSortOrder-int- DefaultRowSorter#toggleSortOrder(int) (Java Platform SE 8)]

* コメント [#comment]
#comment
#comment