---
category: swing
folder: StandingsTables
title: JTableの水平罫線を描画する位置とその色をソート条件に応じて変更する
tags: [JTable, JLayer]
author: aterai
pubdate: 2023-09-18T02:49:36+09:00
description: JTableで順位表を作成し、上位と下位のグループ分けを表す水平罫線をJLayerを使用して描画するよう設定します。
image: https://drive.google.com/uc?id=1UqHCznb6MioPHeaYVnk1_lj3IKz4EM5w
---
* 概要 [#summary]
`JTable`で順位表を作成し、上位と下位のグループ分けを表す水平罫線を`JLayer`を使用して描画するよう設定します。

#download(https://drive.google.com/uc?id=1UqHCznb6MioPHeaYVnk1_lj3IKz4EM5w)

* サンプルコード [#sourcecode]
#code(link){{
class BorderPaintLayerUI extends LayerUI<JScrollPane> {
  @Override public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    JTable table = getTable(c);
    RowSorter<? extends TableModel> sorter = table == null ? null : table.getRowSorter();
    if (Objects.nonNull(sorter)) {
      List<? extends RowSorter.SortKey> keys = sorter.getSortKeys();
      int column = keys.isEmpty() ? -1 : keys.get(0).getColumn();
      if (column <= 0 || column == 9) {
        Graphics2D g2 = (Graphics2D) g.create();
        boolean b1 = column == 0 && keys.get(0).getSortOrder() == SortOrder.ASCENDING;
        boolean b2 = column == 9 && keys.get(0).getSortOrder() == SortOrder.DESCENDING;
        if (column < 0 || b1 || b2) {
          g2.setPaint(Color.GREEN.darker());
          g2.draw(makeUnderline(c, table, 2));
          g2.setPaint(Color.BLUE.darker());
          g2.draw(makeUnderline(c, table, 6));
          g2.setPaint(Color.RED.darker());
          g2.draw(makeUnderline(c, table, 20));
        } else {
          g2.setPaint(Color.GREEN.darker());
          g2.draw(makeUnderline(c, table, 22 - 2));
          g2.setPaint(Color.BLUE.darker());
          g2.draw(makeUnderline(c, table, 22 - 6));
          g2.setPaint(Color.RED.darker());
          g2.draw(makeUnderline(c, table, 22 - 20));
        }
        g2.dispose();
      }
    }
  }

  private static JTable getTable(Component c) {
    JTable table = null;
    if (c instanceof JLayer) {
      Component c1 = ((JLayer<?>) c).getView();
      if (c1 instanceof JScrollPane) {
        table = (JTable) ((JScrollPane) c1).getViewport().getView();
      }
    }
    return table;
  }

  private static Line2D makeUnderline(JComponent c, JTable table, int idx) {
    Rectangle r0 = table.getCellRect(idx - 1, 0, false);
    Rectangle r1 = table.getCellRect(idx - 1, table.getColumnCount() - 1, false);
    Rectangle r = SwingUtilities.convertRectangle(table, r0.union(r1), c);
    return new Line2D.Double(r.getX(), r.getMaxY(), r.getMaxX(), r.getMaxY());
  }
}
}}

* 解説 [#explanation]
- `JTable`のデフォルト罫線を非表示化して順位表を作成
- `JTable`を配置する`JScrollPane`を`JLayer`でラップし、`LayerUI#paint(...)`をオーバーライド
-- ソートなし、または`0`列目(順位)が昇順ソート、`9`列目(勝ち点)が降順ソートされている場合、`1`行目(`2`位)セルと`5`行目(`6`位)セルの下部、`21`行目(`20`位)セルの上部に罫線を描画
-- `0`列目(順位)が降順ソート、または`9`列目(勝ち点)が昇順ソートされている場合、`1`行目(`21`位)セルの下部、`16`行目(`6`位)セルと`20`行目(`2`位)セルの上部に罫線を描画
-- それ以外がソートされている場合は罫線を描画しない

----
- セルの背景色は`JLayer`ではなく`JTable#prepareRenderer(...)`をオーバーライドして順位、奇数・偶数行などに応じて変更
- `8`列目の得失点は正の値の先頭に`+`を付けて文字列で表示するセルレンダラーを設定
- %%たとえば勝点が同じ場合は得失点でソートするような処理には未対応%%
-- [[JTableの行を複数条件でソートする>Swing/StandingsTablesComparator]]のサンプルに勝点が同じ場合は得失点でソートする処理を追加

* 参考リンク [#reference]
- [[JTableのセルを斜めに分割する>Swing/DiagonallySplitCellCalendar]]
- [[JTableが空の場合、中央にJComponentを表示する>Swing/PlaceholderForEmptyTable]]
- [[JTableの行を複数条件でソートする>Swing/StandingsTablesComparator]]

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