一、需要知道的事實:
1、當鼠標懸停在JTable上時,相應的格子(cell)的渲染器(TableCellRenderer)的渲染方法(getTableCellRenererComponent)會被調用,但不夠及時(這一點可以通過在渲染方法里打印一句話來自行測試),
而且只是鼠標覆蓋的格子的渲染方法會被調用,與其同一行的其他格子的渲染方法並未被調用。所以,指望只通過修改渲染器就能達到目的是不可能的了。
2、JTable的所有監聽器都在TableUI(默認使用的是BasicTableUI)中定義,從BasicTableUI源代碼中可以發現,關於鼠標的監聽器,只有MouseInputListener,並不支持對鼠標懸停事件的監聽。所以,如果你
重寫TableUI,給JTable添加鼠標懸停行為事件監聽器應該也可達到目的,但本文不討論這種實現方式。
二、總體思路:
能不能不重寫TableUI,用一個最直接的鼠標監聽器達到目的?
首先自定義TableCellRenderer,通過JTable對象獲取當前鼠標所在行的行號,在渲染方法里根據行號修改背景顏色。
然后給JTable添加一個鼠標行為監聽器(MouseMotionListener),當監聽到JTable的某行上有鼠標懸停時,觸發JTable的prepareRenderer方法,促使JTable相應行中的格子進行渲染。然后調用JTable的repaint。
三、代碼片斷
// 為了簡便,直接在構造JTable時把渲染器里的處理寫在其中了,正常的做法是不需要修改JTable代碼,在自定義的TableCellRenderer中寫這些邏輯。
JTable table = new JTable(model){
@override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column){
Component comp = super.prepareRenderer(renderer,row,column);
Point p = getMousePosition();
if(p!=null){
int rowUnderMouse = rowAtPoint(p);
if(rowUnderMouse = row){
comp.setBackground(Color.red);
}else{
comp.setBackGround(DefaultLookup.getColor(this,ui,"Table.alternateRowColor"));
}
}
return comp;
}
}
class MyTableMouseMotionListener extends MouseMotionAdapter{
private int rowUnderMouse = -1;
@override
public void mouseMoved(MouseEvent e){
JTable table = (JTable)e.getSource();
Point p = table.getMousePosition();
if(p != null){
rowUnderMouse = table.rowAtPoint(p);
if(rowUnderMouse >= 0){
for(int i=0;i<table.getColumnCount();i++){
table.prepareRenderer(table.getCellRenderer(rowUnderMouse,i),rowUnderMouse,i);
if(rowUnderMouse != 0){
table.prepareRenderer(table.getCellRenderer(rowUnderMouse-1,i),rowUnderMouse-1,i);
}
if(rowUnderMouse != table.getRowCount()-1){
table.prepareRenderer(table.getCellRenderer(rowUnderMouse+1,i),rowUnderMouse+1,i);
}
}
table.repaint(table.getVisibleRect());
}
}
}
}
最后,table.addMouseMotionListener(new MyTableMouseMotionListener());
