程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在JTable中實現單元格鼠標懸停效果

在JTable中實現單元格鼠標懸停效果

編輯:關於JAVA

在Google上搜索實現這種效果的方法,只搜到一個網頁,是國外的,一看,還得要給錢注冊!俗話說,自力更生,艱苦奮斗,就自己想了法子,拿來分享。衷心請各位大蝦指點指點不足

我寫了個程序,裡面用到一個JTable,本著MVC的精神,而且考慮到單元格可能不是簡簡單單一個Label能表現的,就寫了個表格渲染器的類,叫NoteLabelRenderer

代碼如下:

//NoteLabelRenderer.Javapackage 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 JTablethat is asking the * renderer to draw; can be null * @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 * value * is the string "true", it could be rendered as a * string or it could be rendered as a check * box that is checked. null 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 * row 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 Note * @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(""+title+"
" + ""+contentText+""); /* *********************** ***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 JTable * A Vector stores information about * whether the cell is beneath the mouse. If the value * corresponding to the cell is true, this method will * return a Component with the border modifIEd; * while false, the Renderer 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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved