Swing/SortingHeaderColumnPainter の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/SortingHeaderColumnPainter へ行く。
- Swing/SortingHeaderColumnPainter の差分を削除
--- 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の背景色などを変更してハイライト表示するよう設定します。 `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); 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); } } }} * Explanation [#explanation] - `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)); 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