自訂 NoteLabelRenderer extends JPanel implements TableCellRenderer,內含三個 JLabel (Icon/Content/Attach)。點選狀態 (isSelected) 好處理,但滑鼠懸停 (rollover) 在 Renderer 加 MouseMotionListener 無效 —— Renderer 只是「橡皮圖章」,不佔據真實組件幾何位置。
rowAtPoint(Point)發現 JTable 有 rowAtPoint 可直接獲取滑鼠下的行號。於是在 JTable 子類掛 MouseMotionListener:
private int mouseAtRow = -1;
private Vector flagMouseOver = new Vector<>(); // 標記每行是否滑鼠懸停
public void mouseMoved(MouseEvent e) {
int row = rowAtPoint(e.getPoint());
if (row == -1) return; // 滑鼠不在表格內
if (mouseAtRow == -1) { // 首次進入
flagMouseOver.set(row, Boolean.TRUE);
mouseAtRow = row;
} else if (row != mouseAtRow) { // 移動到新行
flagMouseOver.set(mouseAtRow, Boolean.FALSE);
flagMouseOver.set(row, Boolean.TRUE);
mouseAtRow = row;
} else return; // 同行無變化
repaint(); revalidate(); // 觸發重繪
}
prepareRenderer 注入懸停邊框public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
if (Boolean.TRUE.equals(flagMouseOver.get(row))) {
((JComponent) comp).setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
} else {
((JComponent) comp).setBorder(null);
}
return comp;
}
prepareRenderer 是 JTable 繪製前準備組件的公共方法,攔截它即可在不修改 Renderer 邏輯下注入懸停樣式 (邊框/背景色均可)。
Renderer 只負責「長什麼樣」,Table 負責「什麼時候長什麼樣」。懸停屬於 Table 級幾何狀態,應在 Table 層處理,配合 prepareRenderer 橋接渲染,乾淨解耦。