通过自定义单元格渲染器在Jtable中显示超链接

转载:http://www.tuicool.com/articles/qE7FNv

在JTable中自定义单元格渲染器是非常简单和容易的。对于单元格渲染器来说,它的主要任务就是为目标单元格返回一个Component对象,以呈现其内容。说到Component,就应该豁然开朗了,因为在Swing中,所有可在屏幕上显示的图形控件都是Component的直接或间接子类,也就是说,理论上你可以在JTable单元格中显示任意图形控件!

当然,实际上有一些控件是不能在单元格中显示的,比如JFrame这样的独立窗口控件,为了避免循环引用也不允许将当前表格作为渲染器,但即便是这样,我们的可用选择仍然多的数不清。我们只需要继承任意可用的Component子类,同时实现TableCellRenderer接口,就可以制作一个自己的单元格渲染器。作为Swing自带的默认单元格渲染器,DefaultTableCellRenderer的使用频率非常高,该类继承自JLabel,是最简单的单元格渲染器实现。参考这一实现,我们可以尝试分别继承自JComboBox、JButton、JCheckBox、JProgressBar等,实现在表格单元格中显示下拉框、按钮、复选框和进度条等稍微高级的UI控件。

值得注意的是,单元格的UI控件没有拦截事件的能力,也就是说,他们仅仅做数据呈现工作,不能够与用户交互(因为事件被JTable在上层拦截并处理),这也意味着某些如下拉框、复选框等可交互的UI控件“只能看不能用”。不过我们可以通过监听JTable的鼠标事件并通过接口转换到对应的单元格和借助单元格编辑器的方式分别解决上述两个问题。

如下代码,演示了如何通过自定义单元格渲染器实现在表格中显示超链接并在链接被点击时自动打开对应页面的功能:

package cn.ysh.studio.jtable;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.MouseInputListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

/**
 * 显示超链接的JTable单元格渲染器
 * @author 杨胜寒
 * @date 2013-06-20 16:08:36
 */
public class LinkCellRenderer extends DefaultTableCellRenderer implements MouseInputListener {

    //鼠标事件所在的行
    private int row = -1;
    //鼠标事件所在的列
    private int col = -1;
    //当前监听的Table
    private JTable table = null;

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        //恢复默认状态
        this.table = table;
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        this.setForeground(Color.black);
        table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        this.setText(value.toString());
        //如果当前需要渲染器的单元格就是鼠标事件所在的单元格
        if (row == this.row && column == this.col) {
            //如果是第二列(第二列是显示超链接的列)
            if (column == 1) {
                //改变前景色(文字颜色)
                this.setForeground(Color.blue);
                //改变鼠标形状
                table.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                //显示超链接样式
                this.setText("<html><u>" + value.toString() + "</u></html>");
            }
            setBackground(table.getSelectionBackground());
        } else if (isSelected) {
            //如果单元格被选中,则改变前景色和背景色
            setForeground(table.getSelectionForeground());
            setBackground(table.getSelectionBackground());
        } else {
            //其他情况下恢复默认背景色
            setBackground(Color.white);
        }
        return this;
    }

    /**
     * 鼠标移出事件
     * @param e
     */
    public void mouseExited(MouseEvent e) {
        if (table != null) {
            int oldRow = row;
            int oldCol = col;
            //鼠标移出目标表格后,恢复行列数据到默认值
            row = -1;
            col = -1;
            //当之前的行列数据有效时重画相关区域
            if (oldRow != -1 && oldCol != -1) {
                Rectangle rect = table.getCellRect(oldRow, oldCol, false);
                table.repaint(rect);
            }
        }
    }

    /**
     * 鼠标拖动事件
     * @param e
     */
    public void mouseDragged(MouseEvent e) {
        mouseMoved(e);
    }

    /**
     * 鼠标移动事件
     * @param e
     */
    public void mouseMoved(MouseEvent e) {
        if (table != null) {
            Point p = e.getPoint();
            int oldRow = row;
            int oldCol = col;
            row = table.rowAtPoint(p);
            col = table.columnAtPoint(p);
            //重画原来的区域
            if (oldRow != -1 && oldCol != -1) {
                Rectangle rect = table.getCellRect(oldRow, oldCol, false);
                table.repaint(rect);
            }
            //重画新的区域
            if (row != -1 && col != -1) {
                Rectangle rect = table.getCellRect(row, col, false);
                table.repaint(rect);
            }
        }
    }

    /**
     * 鼠标单击事件
     * @param e
     */
    public void mouseClicked(MouseEvent e) {
        //获取事件所在的行列坐标信息
        Point p = e.getPoint();
        int c = table.columnAtPoint(p);
        if(c != 1){
            return;
        }
        int r = table.rowAtPoint(p);
        try {
            //取得目标单元格的值,即链接信息
            URL url = new URL(table.getValueAt(r, c).toString());
            //在系统默认浏览器中打开链接
            Desktop.getDesktop().browse(url.toURI());
        } catch (Exception ex) {
            Logger.getLogger(LinkCellRenderer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 鼠标按下事件
     * @param e
     */
    public void mousePressed(MouseEvent e) {
    }

    /**
     * 鼠标释放事件
     * @param e
     */
    public void mouseReleased(MouseEvent e) {
    }

    /**
     * 鼠标进入事件
     * @param e
     */
    public void mouseEntered(MouseEvent e) {
    }

    /**
     * 测试方法
     * @param args
     */
    public static void main(String[] args) {
        //将在表格中呈现的数据
        Object[] header = new String[]{"标题", "链接"};
        Object[][] data = new String[10][2];
        for (int i = 0; i < 10; i++) {
            data[i][0] = "网页标题";
            data[i][1] = "http://www.yshjava.cn/post/529.html";
        }
        //构建表格数据模型
        TableModel model = new DefaultTableModel(data, header);
        //创建表格对象
        JTable table = new JTable(model);
        //创建单元格渲染器暨鼠标事件监听器
        LinkCellRenderer renderer = new LinkCellRenderer();
        //注入渲染器
        table.setDefaultRenderer(Object.class, renderer);
        //注入监听器
        table.addMouseListener(renderer);
        table.addMouseMotionListener(renderer);

        //为表格增加爱滚动窗格
        JScrollPane sp = new JScrollPane(table);
        //创建窗口程序
        JFrame f = new JFrame("JTable 单元格超链接测试");
        f.getContentPane().add(sp, BorderLayout.CENTER);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800, 600);
        f.setLocationRelativeTo(null);
        //显示窗口
        f.setVisible(true);
    }
}

效果图如下所示:

在上面的例子中,仅仅演示了如何通过监听JTable的鼠标事件来影响对应单元格的行为和外观,但是并未涉及到如何解决交互型UI在JTable单元格中不可用的问题。解决这个问题,需要借助TableCellEditor单元格编辑器的配合来实现,简单来说,展现靠渲染器,交互操作靠编辑器。

TableCellEditor跟TableCellRenderer的原理几乎是一样的,都是接口,Swing都提供了简单的默认实现,都负责生成UI控件来展现或供编辑单元格的数据,不同的是TableCellEditor有接收交互事件的能力,而TableCellRenderer没有,因此可以简单认为“编辑器是动态的,负责编辑,而渲染器是静态的,负责展现”。单元格编辑器不是本文的主题,不做过多说明。放一张NetBeans可视化UI设计器的一个窗口截图,图中的表格就是通过自定义渲染器和编辑器实现的。

时间: 2024-10-18 02:39:15

通过自定义单元格渲染器在Jtable中显示超链接的相关文章

Swift - 自定义单元格实现微信聊天界面

1,下面是一个放微信聊天界面的消息展示列表,实现的功能有: (1)消息可以是文本消息也可以是图片消息 (2)消息背景为气泡状图片,同时消息气泡可根据内容自适应大小 (3)每条消息旁边有头像,在左边表示发送方,在右边表示接收方 2,实现思路 (1)需要定义一个数据结构保存消息内容 MessageItem (2)继承UITableViewCell实现自定义单元格,这里面放入头像和消息体 (3)继承UITableView实现自定义表格,通过读取数据源,进行页面的渲染 (4)消息体根据内容类型不同,用不

iOS:UITableViewCell自定义单元格

UITableViewCell:自定义的单元格,可以在xib中创建单元格,也可以在storyBorad中创建单元格.有四种创建方式 <1>在storyBorad中创建的单元格,它是静态的单元格,单元格一开始就存在,可以直接根据自定义的重用标识名加载使用: <2>当然,storyBorad中单元格也可以关联一个自定义的类,这个类必须是继承UITableViewCell,这种情况下,直接根据自定义的重用标识名加载使用也是可以的. <3>在xib中创建的单元格,如果直接通过b

IOS学习之——表视图3 自定义单元格

写在前面 今天看新闻,科比肩部撕裂,可能会提前退役,这个顽固的男人,终于要落幕了,虽然我不是他的球迷,也是心生敬仰,今天的主题就以科比为素材,向这位人生的斗士致敬. 前面我们讲到了tableview的单元格的系统自带的image label,用起来很方便,可是毕竟限制很多,这一篇将会讲到一个神奇的东西--自定义单元格,由你控制单元格显示的内容,位置,形式.如下图,我们要制作一个球星列表,需要四项信息:头像+姓名+年龄+性别 设置界面 拖控件,如下图 设置单元格高度,这里要讲一下高度有两个: 设置

浅谈DevExpress&lt;五&gt;:TreeList简单的美化——自定义单元格,加注释以及行序号

今天就以昨天的列表为例,实现以下效果:预算大于110万的单元格突出显示,加上行序号以及注释,如下图: 添加行序号要用到CustomDrawNodeIndicator方法,要注意的是,取得的节点索引是从0开始的,所以要+1以便第一行从一开始算起. private void treeList1_CustomDrawNodeIndicator(object sender, CustomDrawNodeIndicatorEventArgs e) { TreeList tree = sender as D

jQuery MiniUI自定义单元格

监听处理"drawcell"事件 使用"drawcell"事件,可以自定义单元格内容.样式.行样式等. grid.on("drawcell", function (e) { var record = e.record, column = e.column, field = e.field, value = e.value; //格式化日期 if (field == "birthday") { if (mini.isDate(v

Objective-C:UITableViewCell自定义单元格

UITableViewCell:自定义的单元格,可以在xib中创建单元格,也可以在storyBorad中创建单元格.有四种创建方式 <1>在storyBorad中创建的单元格,它是静态的单元格,单元格一开始就存在,可以直接根据自定义的重用标识名加载使用: <2>当然,storyBorad中单元格也可以关联一个自定义的类,这个类必须是继承UITableViewCell,这种情况下,直接根据自定义的重用标识名加载使用也是可以的. <3>在xib中创建的单元格,如果直接通过b

自定义单元格(IOS)

自定义单元格有三种方法 - 代码实现 - xib - storyboard(推荐) 在故事板中操作方法为 1.在TableView属性的Prototype Cells设置为1,默认为1: 2.需要创建自定义的单元格类: 3.设定Table View Cell的Class为自定义类: 自定义类:(并不难) #import "CustomCell.h" @implementation CustomCell - (void)awakeFromNib { // Initialization c

自定义单元格

在cs代码中完成 自定义单元格 public class EmployeeCell : ViewCell { public EmployeeCell() { var image = new Image { HorizontalOptions = LayoutOptions.Start }; image.SetBinding(Image.SourceProperty, new Binding("ImageUri")); //设置宽高为40 image.WidthRequest = ima

NPOI 自定义单元格背景颜色-Excel

2016-12-27 10:44 by 杨新华, 5242 阅读, 0 评论, 收藏, 编辑 NPOI针对office2003使用HSSFWorkbook,对于offce2007及以上使用XSSFWorkbook:今天我以HSSFWorkbook自定义颜色为例说明,Office2007的未研究呢 在NPOI中默认的颜色类是HSSFColor,它内置的颜色有几十种供我们选择,如果不够怎么办,不能修改底层的HSSFColor类: 大概解决思路: 1.将颜色的RGB值添加进调色板HSSFPalette