---
category: swing
folder: SortingHeaderColumnPainter
title: TableColumnのソート状態をハイライト描画する
tags: [TableColumn, JTableHeader, JTable, JLayer, TableRowSorter, TableCellRenderer]
author: aterai
pubdate: 2025-05-05T03:33:57+09:00
description: JTableでソート中のTableColumnの背景色などを変更してハイライト表示するよう設定します。
image: https://drive.google.com/uc?id=10W3RJ-aV4ERfuVc3rC3wsyn0X2-3S0Bx
---
* Summary [#summary]
`JTable`でソート中の`TableColumn`の背景色などを変更してハイライト表示するよう設定します。
#download(https://drive.google.com/uc?id=10W3RJ-aV4ERfuVc3rC3wsyn0X2-3S0Bx)
* Source Code Examples [#sourcecode]
#code(link){{
class ColumnHeaderRenderer implements TableCellRenderer {
private static final Color SORTING_BGC = new Color(0xA4_CF_EF);
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
boolean b = isSortingColumn(table, column) || isSelected;
Component c = r.getTableCellRendererComponent(
table, value, b, hasFocus, row, column);
if (b) {
c.setBackground(SORTING_BGC);
}
return c;
}
private static boolean isSortingColumn(JTable table, int column) {
return Optional.ofNullable(table.getRowSorter()).map(RowSorter::getSortKeys)
.filter(keys -> !keys.isEmpty())
.map(keys -> keys.get(0).getColumn())
.map(i -> column == table.convertColumnIndexToView(i)).orElse(false);
}
}
}}
* Description [#explanation]
* Description [#description]
- `HeaderRenderer`
-- `TableColumn`がソート中の場合は選択状態で背景を描画する`TableCellRenderer`を作成し、これをすべての`HeaderRenderer`に`TableColumn#setHeaderRenderer(...)`で設定
-- `NimbusLookAndFeel`などではデフォルトでソート中の`TableColumn`はハイライト描画され、上記の`TableCellRenderer`で指定した背景色は無効
-- [[JTableでソート中のカラムセル色>Swing/SortColumnColor]]
-- [[JTableHeaderのハイライト表示>Swing/ColumnHeaderHighlight]]
- `JLayer`
-- `JTableHeader`を配置する親`JScrollPane`に`JLayer`を設定してソート中の`TableColumn`領域を取得し、半透明の下線をハイライトとして描画
-- `NimbusLookAndFeel`などでも`JLayer`で上書きしているのでハイライト色を指定可能
-- ソート中の`TableColumn`文字列を上書きしないよう、`TableColumn`全体ではなく下線のみ描画
-- ソート中の`TableColumn`がマウスドラッグで入れ替え中の場合は、`TableColumn`の位置を`JTableHeader#getDraggedDistance()`で補正する必要がある
-- [[TableColumnのドラッグによる順序変更が可能な領域を制限する>Swing/TableColumnReorderingIcon]]
#code{{
class SortingLayerUI extends LayerUI<JScrollPane> {
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (c instanceof JLayer) {
JLayer<?> layer = (JLayer<?>) c;
Rectangle r = getTable(layer)
.map(table -> getSortingColumnBounds(layer, table))
.orElseGet(Rectangle::new);
if (!r.isEmpty()) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(new Color(0x64_FE_AE_FF, true));
g2.fill(r);
g2.dispose();
}
}
}
@Override protected void processMouseEvent(
MouseEvent e, JLayer<? extends JScrollPane> l) {
super.processMouseEvent(e, l);
Component c = e.getComponent();
if (c instanceof JTableHeader && e.getID() == MouseEvent.MOUSE_CLICKED) {
c.repaint();
}
}
@Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JScrollPane> l) {
Component c = e.getComponent();
if (c instanceof JTableHeader && e.getID() == MouseEvent.MOUSE_DRAGGED) {
c.repaint();
}
}
private static Optional<JTable> getTable(JLayer<?> layer) {
return Optional.ofNullable(layer.getView())
.filter(JScrollPane.class::isInstance)
.map(JScrollPane.class::cast)
.map(JScrollPane::getViewport)
.map(JViewport::getView)
.filter(JTable.class::isInstance)
.map(JTable.class::cast);
}
private static int getSortingColumnIndex(JTable table) {
return Optional.ofNullable(table.getRowSorter())
.map(RowSorter::getSortKeys)
.filter(keys -> !keys.isEmpty())
.map(keys -> keys.get(0).getColumn())
.map(table::convertColumnIndexToView)
.orElse(-1);
}
private static Rectangle getSortingColumnBounds(JLayer<?> layer, JTable table) {
Rectangle rect = new Rectangle();
int sortingColumn = getSortingColumnIndex(table);
if (sortingColumn >= 0) {
Rectangle r = getSortingRect(table, sortingColumn);
int h = r.height / 6;
r.y += r.height - h;
r.height = h;
rect.setRect(SwingUtilities.convertRectangle(
table.getTableHeader(), r, layer));
}
return rect;
}
private static Rectangle getSortingRect(JTable table, int sortingColumn) {
JTableHeader header = table.getTableHeader();
Rectangle r = header.getHeaderRect(sortingColumn);
TableColumn draggedColumn = header.getDraggedColumn();
if (draggedColumn != null) {
int modelIndex = draggedColumn.getModelIndex();
int viewIndex = table.convertColumnIndexToView(modelIndex);
if (viewIndex == sortingColumn) {
r.x += header.getDraggedDistance();
}
}
return r;
}
}
}}
* Reference [#reference]
- [[JTableでソート中のカラムセル色>Swing/SortColumnColor]]
- [[JTableHeaderのハイライト表示>Swing/ColumnHeaderHighlight]]
- [[TableColumnのドラッグによる順序変更が可能な領域を制限する>Swing/TableColumnReorderingIcon]]
* Comment [#comment]
#comment
#comment