王朝网络
分享
 
 
 

在JTable中实现单元格鼠标悬停效果

王朝other·作者佚名  2006-05-27
宽屏版  字体: |||超大  

在Google上搜索实现这种效果的方法,只搜到一个网页,是国外的,一看,还得要给钱注册!

俗话说,自力更生,艰苦奋斗,就自己想了法子,拿来分享。衷心请各位大虾指点指点不足

我写了个程序,里面用到一个JTable,本着MVC的精神,而且考虑到单元格可能不是简简单单一个Label能表现的,就写了个表格渲染器的类,叫NoteLabelRenderer

代码如下:

//NoteLabelRenderer.java

package com.component;

import javax.swing.*;

import javax.swing.table.*;

import java.awt.*;

import com.data.Note;

/**

* To render the cells showing the note

* @author Allen Chue

*

*/

public class NoteLabelRenderer extends JPanel implements TableCellRenderer {

public static ImageIcon ATTACH_ICON=new ImageIcon("res/attach.gif");

public static ImageIcon BLANK_ICON=new ImageIcon("res/blank.gif");

private JLabel icon=new JLabel();

private JLabel content=new JLabel();

private JLabel attach=new JLabel();

private String contentText,title;

public NoteLabelRenderer() {

super();

setLayout(new BorderLayout());

icon.setOpaque(true);

content.setOpaque(true);

attach.setOpaque(true);

icon.setHorizontalAlignment(SwingConstants.CENTER);

icon.setVerticalAlignment(SwingConstants.CENTER);

content.setVerticalAlignment(SwingConstants.NORTH);

attach.setHorizontalAlignment(SwingConstants.CENTER);

attach.setVerticalAlignment(SwingConstants.CENTER);

add(icon,BorderLayout.WEST);

add(content,BorderLayout.CENTER);

add(attach,BorderLayout.EAST);

setSize(getPreferredSize());

}

/**

* Returns the component used for drawing the cell. This method is

* used to configure the renderer appropriately before drawing.

*

* @param table the <code>JTable</code> that is asking the

* renderer to draw; can be <code>null</code>

* @param value the value of the cell to be rendered. It is

* up to the specific renderer to interpret

* and draw the value. For example, if

* <code>value</code>

* is the string "true", it could be rendered as a

* string or it could be rendered as a check

* box that is checked. <code>null</code> is a

* valid value

* @param isSelected true if the cell is to be rendered with the

* selection highlighted; otherwise false

* @param hasFocus if true, render cell appropriately. For

* example, put a special border on the cell, if

* the cell can be edited, render in the color used

* to indicate editing

* @param row the row index of the cell being drawn. When

* drawing the header, the value of

* <code>row</code> is -1

* @param column the column index of the cell being drawn

*/

public Component getTableCellRendererComponent(JTable table, Object value,

boolean isSelected, boolean hasFocus, int row, int column) {

changeBackground(isSelected);

setNoteText((Note)value,isSelected);

return this;

}

private void changeBackground(boolean isSelected) {

Color selectedColor=new Color(160,231,160);

if (isSelected) {

icon.setBackground(selectedColor);

content.setBackground(selectedColor);

attach.setBackground(selectedColor);

}

else {

icon.setBackground(null);

content.setBackground(null);

attach.setBackground(null);

}

}

/**

* Show the note according to a note

* @param n The <code>Note</code>

* @param flag A flag variable. True for emphasizing the the

* contents, while false for showing it normally

*/

private void setNoteText(Note n, boolean flag) {

String color=flag?"#ffffff":"#000000";

/*

************************

*****Set Icon Area******

************************

*/

icon.setIcon(n.getIcon());

/*

************************

****Set Content Area****

************************

*/

title=n.getTitle();

contentText=n.getContent();

if (contentText.length()>120) {

contentText=contentText.substring(0,115)+"...";

}

content.setText("<html><font" +

" color=#116677>"+title+"</font><br>" +

"<font color="+color+">"+contentText+"</font></html>");

/*

***********************

***Set Attach Area*****

***********************

*/

if (n.getAttach() != null) {

attach.setIcon(ATTACH_ICON);

}

else {

attach.setIcon(BLANK_ICON);

}

}

public String getContent() {

return this.contentText;

}

public String getTitle() {

return this.title;

}

}

这是个备忘的程序,一些有Note字眼的不用关心。

这个NoteLableRenderer继承了JPanel,是为了更好地对其中一些组件进行布局的控制(在这里,每个单元格里有三个JLabel),TableCellRender接口是必须要实现的

可以看到,实现鼠标点击单元格改变文字颜色和单元格(也就是一个JPanel)背景色并不难,只需要在getTableCellRendererComponent方法中判断传入的参数isSelected是否为true,然后对组件属性重新设置,返回修改过的Component即可。JTable在鼠标点击单元格时会重画表格,于是改变后的单元格即可显示出来。

我还想要实现单元格的悬停效果,也就是说,当鼠标移动至某个单元格上方时,该单元格可以变化颜色或者加个边框来突出显示,就想JButton可以设置RollOverIcon一样。我想当然地在这个渲染器里添加了鼠标监听,然而测试确发现不行...

经过一番查阅、思考,我终于将解决的方法从单元格渲染器上转至JTable本身来,因为我发现JTable里竟然有个rowAtPoint(Point point)方法(高手可不要笑我啊)!于是,我就在表格上监听鼠标动作事件,在mouseMoved(MouseEvent e)方法中用int row=this.rowAt(e.getPoint())得到鼠标移动时当前鼠标在哪一行。这样的话,至少是迈了一大步,接下来的问题就是如何对鼠标下面的单元格进行属性的修改。

经过查看JTable的源码,发现里面有个public Component prepareRenderer方法调用了单元格渲染器里的getTableCellRenderer方法,用于在绘制表格时准备好单元格内放置的组件。既然它是public的,我就重载了这个方法,并使用了个自己感觉有点笨的方法,表格中加了个Vector,存储每个单元格是否在鼠标下面的信息(用Boolean),也就是说,每一时刻这个Vector中只有一个为true(同一时刻,只能有一个单元格在鼠标下面),其余为false,同时保持Vector的size与单元格行数相同。

重载的prepareRenderer方法体如下:

/**

* This method overides the super one, in order to

* add rollover effects to the <code>JTable</code>

* A <code>Vector</code> stores information about

* whether the cell is beneath the mouse. If the value

* corresponding to the cell is true, this method will

* return a <code>Component</code> with the border modified;

* while false, the <code>Renderer</code> will be returned

* unchanged after calling the super method

*/

public Component prepareRenderer(TableCellRenderer renderer, int row,

int column) {

Component comp = super.prepareRenderer(renderer, row, column);

if (((Boolean)flagMouseOver.get(row)).booleanValue()) {

((JComponent)comp).setBorder(BorderFactory.createLineBorder(Color.GRAY,1));

return comp;

}

else {

((JComponent)comp).setBorder(null);

return comp;

}

}

flagMouseOver即为保存单元格状态的Vector。而mouseMoved方法如下

public void mouseMoved(MouseEvent e) {//Add rollover effects

int row=this.rowAtPoint(e.getPoint());

if (mouseAtRow == -1) {

//Init variable mouseAtRow

mouseAtRow=row;

flagMouseOver.set(mouseAtRow,new Boolean(true));

//System.out.println("Mouse first moves to row "+(row+1));

repaint();

revalidate();

}

else if (row != mouseAtRow) {//The mouse has moved to a new row

//Clear the border

flagMouseOver.set(mouseAtRow,new Boolean(false));

//Set new row's border

flagMouseOver.set(row,new Boolean(true));

//System.out.println("Mouse moves from row "+(mouseAtRow+1)+" to row "+(row+1));

repaint();

revalidate();

mouseAtRow=row;

}

}

mouseAtRow为一个int类型的变量,存储鼠标移动前在哪一行。当鼠标移动时,获得当前鼠标在哪一行(表格仅有一列),然后与mouseAtRow比较,若变化了,说明鼠标到了新的一行,同时更新flagMouseOver内的数据,紧接着用repaint和revalidate方法更新表格,实现了表格GUI的变化。这里悬停效果是添加边框,当然也可以改背景等等。

这是我的经历,希望有人提出意见,我非常欢迎!

Allen Chue

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有