---
category: swing
folder: RoundedCornerTableRowSelection
title: JTableの行選択背景描画をラウンド矩形に変更する
tags: [JTable, TableCellRenderer]
author: aterai
pubdate: 2024-04-08T04:32:15+09:00
description: JTableの行選択背景が行全体でラウンド矩形になるよう先頭・末尾セルのTableCellRendererで角を丸めて描画します。
image: https://drive.google.com/uc?id=1qsuWnjpaJmbyjNO6RsU9kv_JSIUpxTGY
---
* Summary [#summary]
`JTable`の行選択背景が行全体でラウンド矩形になるよう先頭・末尾セルの`TableCellRenderer`で角を丸めて描画します。
#download(https://drive.google.com/uc?id=1qsuWnjpaJmbyjNO6RsU9kv_JSIUpxTGY)
* Source Code Examples [#sourcecode]
#code(link){{
class RoundSelectionRenderer extends DefaultTableCellRenderer {
private static final double ARC = 6d;
private Position pos;
@Override public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground().brighter());
double w = getWidth() - 1d;
double h = getHeight() - 1d;
Area area = pos.getArea(w, h, ARC);
g2.fill(area);
if (isFocusable()) {
g2.setColor(getBackground());
g2.draw(area);
}
super.paintComponent(g);
g2.dispose();
}
@Override public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
Component c = super.getTableCellRendererComponent(
table, value, isSelected, false, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
l.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
l.setOpaque(false);
pos = getPosition(table, column);
boolean b = value instanceof Number;
l.setHorizontalAlignment(b ? RIGHT : LEFT);
}
c.setFocusable(hasFocus
|| table.getSelectionModel().getLeadSelectionIndex() == row);
return c;
}
private static Position getPosition(JTable table, int column) {
boolean isFirst = column == 0;
boolean isLast = column == table.getColumnCount() - 1;
Position p;
if (isFirst) {
p = Position.FIRST;
} else if (isLast) {
p = Position.LAST;
} else {
p = Position.MIDDLE;
}
return p;
}
private enum Position {
FIRST, MIDDLE, LAST;
public Area getArea(double w, double h, double arc) {
Area area = new Area();
if (this == FIRST) {
area.add(new Area(new Rectangle2D.Double(w - arc, 0d, arc + arc, h)));
area.add(new Area(new RoundRectangle2D.Double(0d, 0d, w, h, arc, arc)));
} else if (this == LAST) {
area.add(new Area(new Rectangle2D.Double(-arc, 0d, arc + arc, h)));
area.add(new Area(new RoundRectangle2D.Double(0d, 0d, w, h, arc, arc)));
} else {
area.add(new Area(new Rectangle2D.Double(-arc, 0d, w + arc + arc, h)));
}
return area;
}
}
}
}}
* Description [#explanation]
* Description [#description]
- `JTable#setShowGrid(false)`で罫線を非表示、`JTable#setRowHeight(24)`で行の高さを拡大、`JTable#setIntercellSpacing(new Dimension(0, 3))`で列の隙間を`0`に縮小、行の隙間を`3`に拡大して行選択描画が重ならないよう設定(`Windows 11`のファイルエクスプローラー風)
- `DefaultTableCellRenderer#paintComponent(...)`をオーバーライドして先頭、末尾、それ以外のセルで選択背景の描画を変更
-- 先頭セル(`column == 0`)の場合は左端を`RoundRectangle2D`、右端をセル幅を右側方向にはみ出す`Rectangle2D`で作成した`Area`で選択背景を描画
--- フォーカス用の罫線も上記の`Area`を使用して描画
--- 右端の罫線はセル外で非表示になり、となりのセルと連続しているように表示される
-- 末尾セル(`column == table.getColumnCount() - 1`)の場合は右端を`RoundRectangle2D`、左端をセル幅を左側方向にはみ出す`Rectangle2D`で作成した`Area`で選択背景を描画
--- 先頭セル同様、左端の罫線はセル外で非表示
-- それ以外の中間セルの場合そのセル領域を左右にはみ出す`Rectangle2D`を作成して選択背景として描画
--- 左右の罫線はセル外で非表示
* Reference [#reference]
- [[JTableHeaderの角を丸める>Swing/RoundedCornerTableHeader]]
-- 同様に先頭・末尾ヘッダセルの`TableCellRenderer`で角を丸めているが、ヘッダなのでフォーカス罫線は考慮していない
- [[JTableのセル選択背景描画をラウンド矩形に変更する>Swing/RoundedCellSelectionTable]]
-- 行選択ではなくセル選択でラウンド矩形化するサンプル
* Comment [#comment]
#comment
#comment