JTableHeaderをリンク風に表示しセル内余白のクリックを無効にする
Total: 881
, Today: 1
, Yesterday: 2
Posted by aterai at
Last-modified:
概要
JTableHeader
の列文字列をリンク風に表示し、そのリンク以外のセル内余白をクリックしても列ソートを実行しないよう設定します。
Screenshot
Advertisement
サンプルコード
class HyperlinkHeaderCellRenderer
extends DefaultTableCellRenderer
implements MouseInputListener {
private final Border border = BorderFactory.createCompoundBorder(
BorderFactory.createMatteBorder(0, 0, 1, 0, Color.GRAY),
BorderFactory.createEmptyBorder(4, 1, 3, 2));
private final Color alphaZero = new Color(0x0, true);
private int col = -1;
@Override public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
String str = Objects.toString(value, "");
String sort = "";
RowSorter<? extends TableModel> sorter = table.getRowSorter();
if (Objects.nonNull(sorter) && !sorter.getSortKeys().isEmpty()) {
RowSorter.SortKey sortKey = sorter.getSortKeys().get(0);
if (column == sortKey.getColumn()) {
String k = sortKey.getSortOrder() == SortOrder.ASCENDING
? "▴"
: "▾";
sort = "<small>" + k;
}
}
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
if (this.col == column) {
l.setText("<html><u><font color='blue'>" + str + "</u>" + sort);
} else if (hasFocus) {
l.setText("<html><font color='blue'>" + str + sort);
} else {
l.setText("<html>" + str + sort);
}
l.setHorizontalAlignment(SwingConstants.LEADING);
l.setOpaque(false);
l.setBackground(alphaZero);
l.setForeground(Color.BLACK);
l.setBorder(border);
}
return c;
}
@Override public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.height = 24;
return d;
}
private Rectangle getTextRect(JTableHeader header, int idx) {
JTable table = header.getTable();
TableCellRenderer hr = table.getTableHeader().getDefaultRenderer();
Object headerValue = header
.getColumnModel().getColumn(idx).getHeaderValue();
String str = Objects.toString(headerValue, "");
Component c = hr.getTableCellRendererComponent(
table, headerValue, false, true, 0, idx);
Rectangle viewRect = new Rectangle(header.getHeaderRect(idx));
Rectangle iconRect = new Rectangle();
Rectangle textRect = new Rectangle();
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
Insets ins = l.getInsets();
viewRect.x += ins.left;
viewRect.width -= ins.left + ins.right;
SwingUtilities.layoutCompoundLabel(
header,
header.getFontMetrics(header.getFont()),
str,
l.getIcon(),
l.getVerticalAlignment(),
l.getHorizontalAlignment(),
l.getVerticalTextPosition(),
l.getHorizontalTextPosition(),
viewRect,
iconRect,
textRect,
l.getIconTextGap());
}
return textRect;
}
@Override public void mouseMoved(MouseEvent e) {
JTableHeader header = (JTableHeader) e.getComponent();
int ci = header.columnAtPoint(e.getPoint());
col = getTextRect(header, ci).contains(e.getPoint()) ? ci : -1;
header.repaint(header.getHeaderRect(ci));
}
@Override public void mouseExited(MouseEvent e) {
col = -1;
e.getComponent().repaint();
}
@Override public void mouseClicked(MouseEvent e) {
JTableHeader header = (JTableHeader) e.getComponent();
JTable table = header.getTable();
int ci = header.columnAtPoint(e.getPoint());
int idx = table.convertColumnIndexToModel(ci);
if (getTextRect(header, ci).contains(e.getPoint())) {
RowSorter<?> sorter = table.getRowSorter();
if (sorter instanceof DefaultRowSorter) {
((DefaultRowSorter<?, ?>) sorter).setSortable(idx, true);
sorter.toggleSortOrder(idx);
((DefaultRowSorter<?, ?>) sorter).setSortable(idx, false);
}
}
}
@Override public void mouseDragged(MouseEvent e) {
/* not needed */
}
@Override public void mouseEntered(MouseEvent e) {
/* not needed */
}
@Override public void mousePressed(MouseEvent e) {
/* not needed */
}
@Override public void mouseReleased(MouseEvent e) {
/* not needed */
}
}
View in GitHub: Java, Kotlin解説
TableCellRenderer#getTableCellRendererComponent(...)
をオーバーライド- マウスカーソルが列文字列上に存在する場合は
html
の<u>
タグで列文字列下線を引く - ソートキー状態も列文字列の末尾に
<small>▾
などを追加して表示
- マウスカーソルが列文字列上に存在する場合は
MouseInputListener#mouseClicked(...)
をオーバーライド- 初期状態ではすべての列のソートを無効化し、列文字列がクリックされた場合のみその列のソートを可能にしてから
RowSorter#toggleSortOrder(idx)
でソートし、直後にまた列をソート不可に設定
- 初期状態ではすべての列のソートを無効化し、列文字列がクリックされた場合のみその列のソートを可能にしてから
MouseInputListener#mouseMoved(...)
をオーバーライド- マウスカーソルが列文字列上に存在する場合はその列番号を設定して列ヘッダを再描画
SwingUtilities.layoutCompoundLabel(...)
- マウスカーソルが列文字列上に存在するかどうかは
SwingUtilities.layoutCompoundLabel(...)
メソッドで取得した文字列領域を使用して判断する DefaultTableCellRenderer
がJLabel
を継承しているのでSwingUtilities.layoutCompoundLabel(...)
メソッドで文字列領域が取得可能
- マウスカーソルが列文字列上に存在するかどうかは