TableColumnのソート状態をハイライト描画する
Total: 70
, Today: 2
, Yesterday: 1
Posted by aterai at
Last-modified:
Summary
JTable
でソート中のTableColumn
の背景色などを変更してハイライト表示するよう設定します。
Screenshot

Advertisement
Source Code Examples
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);
}
}
View in GitHub: Java, KotlinExplanation
HeaderRenderer
TableColumn
がソート中の場合は選択状態で背景を描画するTableCellRenderer
を作成し、これをすべてのHeaderRenderer
にTableColumn#setHeaderRenderer(...)
で設定NimbusLookAndFeel
などではデフォルトでソート中のTableColumn
はハイライト描画され、上記のTableCellRenderer
で指定した背景色は無効- JTableでソート中のカラムセル色
- JTableHeaderのハイライト表示
JLayer
JTableHeader
を配置する親JScrollPane
にJLayer
を設定してソート中のTableColumn
領域を取得し、半透明の下線をハイライトとして描画NimbusLookAndFeel
などでもJLayer
で上書きしているのでハイライト色を指定可能- ソート中の
TableColumn
文字列を上書きしないよう、TableColumn
全体ではなく下線のみ描画 - ソート中の
TableColumn
がマウスドラッグで入れ替え中の場合は、TableColumn
の位置をJTableHeader#getDraggedDistance()
で補正する必要がある - TableColumnのドラッグによる順序変更が可能な領域を制限する
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;
}
}