JTable 为单元格添加按钮效果和事件效果

一、添加按钮显示效果

在JTable中,单元格的数据默认是Label的效果,也没有事件。

如果要为单元格添加一个按钮显示效果的话,那么就需要使用到一个swing的接口:javax.swing.table.TableCellRenderer,来改变单元桥格的默认默认渲染方法(DefaultTableCellRenderer),

实现的自定义的渲染器如下:

 
package org.sky.table.render;

import java.awt.Component;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class MyButtonRender implements TableCellRenderer
{
    private JPanel panel;

    private JButton button;

    public MyButtonRender()
    {
        this.initButton();

        this.initPanel();

        // 添加按钮。
        this.panel.add(this.button);
    }

    private void initButton()
    {
        this.button = new JButton();

        // 设置按钮的大小及位置。
        this.button.setBounds(0, 0, 50, 15);

        // 在渲染器里边添加按钮的事件是不会触发的
        // this.button.addActionListener(new ActionListener()
        // {
        //
        // public void actionPerformed(ActionEvent e)
        // {
        // // TODO Auto-generated method stub
        // }
        // });

    }

    private void initPanel()
    {
        this.panel = new JPanel();

        // panel使用绝对定位,这样button就不会充满整个单元格。
        this.panel.setLayout(null);
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
            int column)
    {
        // 只为按钮赋值即可。也可以作其它操作,如绘背景等。
        this.button.setText(value == null ? "" : String.valueOf(value));

        return this.panel;
    }

}

 

修改表格的渲染器:this.table.getColumnModel().getColumn(2).setCellRenderer(new MyButtonRender());//只有获取到表格的列后才能添加渲染器。

 

二、添加事件

通过第一部已经为表格添加了默认的渲染器,但是还无法触发事件,触发事件是没有反应的,因为在点击表格时,会触发表格的编辑事件,而要想触发渲染的按钮的事件,还需要通过修改表格的默认编辑器来实现:

package org.sky.table.editor; 
import java.awt.Component; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
 
import javax.swing.DefaultCellEditor; 
import javax.swing.JButton; 
import javax.swing.JPanel; 
import javax.swing.JTable; 
import javax.swing.JTextField; 
 
/**
 * 自定义一个往列里边添加按钮的单元格编辑器。最好继承DefaultCellEditor,不然要实现的方法就太多了。
 * 
 */ 
public class MyButtonEditor extends DefaultCellEditor 

 
    /**
     * serialVersionUID
     */ 
    private static final long serialVersionUID = -6546334664166791132L; 
 
    private JPanel panel; 
 
    private JButton button; 
 
    public MyButtonEditor() 
    { 
        // DefautlCellEditor有此构造器,需要传入一个,但这个不会使用到,直接new一个即可。  
        super(new JTextField()); 
 
        // 设置点击几次激活编辑。  
        this.setClickCountToStart(1); 
 
        this.initButton(); 
 
        this.initPanel(); 
 
        // 添加按钮。  
        this.panel.add(this.button); 
    } 
 
    private void initButton() 
    { 
        this.button = new JButton(); 
 
        // 设置按钮的大小及位置。  
        this.button.setBounds(0, 0, 50, 15); 
 
        // 为按钮添加事件。这里只能添加ActionListner事件,Mouse事件无效。  
        this.button.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent e) 
            { 
                // 触发取消编辑的事件,不会调用tableModel的setValue方法。  
                MyButtonEditor.this.fireEditingCanceled(); 
 
                // 这里可以做其它操作。  
                // 可以将table传入,通过getSelectedRow,getSelectColumn方法获取到当前选择的行和列及其它操作等。  
            } 
        }); 
 
    } 
 
    private void initPanel() 
    { 
        this.panel = new JPanel(); 
 
        // panel使用绝对定位,这样button就不会充满整个单元格。  
        this.panel.setLayout(null); 
    } 
 
 
    /**
     * 这里重写父类的编辑方法,返回一个JPanel对象即可(也可以直接返回一个Button对象,但是那样会填充满整个单元格)
     */ 
    @Override 
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 
    { 
        // 只为按钮赋值即可。也可以作其它操作。  
        this.button.setText(value == null ? "" : String.valueOf(value)); 
 
        return this.panel; 
    } 
 
    /**
     * 重写编辑单元格时获取的值。如果不重写,这里可能会为按钮设置错误的值。
     */ 
    @Override 
    public Object getCellEditorValue() 
    { 
        return this.button.getText(); 
    } 
 

修改表格的默认编辑器:

this.table.getColumnModel().getColumn(2).setCellEditor(new MyButtonEditor());

 

这样后就能基本达到效果了。但是还要注意,对列2来说,还需要启用可编辑功能,才行,不然仍然触发不了事件的。

代码片段:

public boolean isCellEditable(int row, int column) 

    // 带有按钮列的功能这里必须要返回true不然按钮点击时不会触发编辑效果,也就不会触发事件。  
    if (column == 2) 
    { 
        return true; 
    } 
    else 
    { 
        return false; 
    } 

三、测试代码:

测试代码的界面是由windowbuilder插件生成的,懒得自己去写干净的代码了,所以下边的代码有点冗余,大家看表格下边的那段代码即可:

package org.sky.table.frame; 
 
import java.awt.EventQueue; 
 
public class TestTable 

 
    private JFrame frame; 
    private JTable table; 
 
    /**
     * Launch the application.
     */ 
    public static void main(String[] args) 
    { 
        EventQueue.invokeLater(new Runnable() 
        { 
            public void run() 
            { 
                try 
                { 
                    TestTable window = new TestTable(); 
                    window.frame.setVisible(true); 
                } 
                catch (Exception e) 
                { 
                    e.printStackTrace(); 
                } 
            } 
        }); 
    } 
 
    /**
     * Create the application.
     */ 
    public TestTable() 
    { 
        this.initialize(); 
    } 
 
    /**
     * Initialize the contents of the frame.
     */ 
    private void initialize() 
    { 
        this.frame = new JFrame(); 
        this.frame.setBounds(100, 100, 450, 300); 
        this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        this.frame.getContentPane().setLayout(null); 
 
        JPanel panel = new JPanel(); 
        panel.setBounds(10, 10, 414, 242); 
        this.frame.getContentPane().add(panel); 
        panel.setLayout(null); 
 
        JScrollPane scrollPane = new JScrollPane(); 
        scrollPane.setBounds(10, 10, 394, 222); 
        panel.add(scrollPane); 
 
        this.table = new JTable(); 
        scrollPane.setViewportView(this.table); 
 
        this.table.setModel(new DefaultTableModel() 
        { 
            @Override 
            public Object getValueAt(int row, int column) 
            { 
                return (row + 1) * (column + 1); 
            } 
 
            @Override 
            public int getRowCount() 
            { 
                return 3; 
            } 
 
            @Override 
            public int getColumnCount() 
            { 
                return 3; 
            } 
 
            @Override 
            public void setValueAt(Object aValue, int row, int column) 
            { 
                System.out.println(aValue + "  setValueAt"); 
            } 
 
            @Override 
            public boolean isCellEditable(int row, int column) 
            { 
                // 带有按钮列的功能这里必须要返回true不然按钮点击时不会触发编辑效果,也就不会触发事件。  
                if (column == 2) 
                { 
                    return true; 
                } 
                else 
                { 
                    return false; 
                } 
            } 
        }); 
 
        this.table.getColumnModel().getColumn(2).setCellEditor(new MyButtonEditor()); 
 
        this.table.getColumnModel().getColumn(2).setCellRenderer(new MyButtonRender()); 
 
        this.table.setRowSelectionAllowed(false);// 禁止表格的选择功能。不然在点击按钮时表格的整行都会被选中。也可以通过其它方式来实现。  
    } 
使用 AbstractTableModel 构建Table 在表格中添加JButton按钮,之前在网上找了2天没有找到好用的程序,最终终于找到一个好用的例子。 不要使,我退你们分。。 sing the Swing JTable class can quickly become a sticky business when you want to customize it to your specific needs. First you must become familiar with how the JTable class is organized. Individual cells are rendered by TableCellRenderer implementations. The table contents are represented by an implementation of the TableModel interface. By default, JTable uses DefaultTableCellRenderer to draw its cells. DefaultTableCellRenderer recognizes a few primitive types, rendering them as strings, and can even display Boolean types as checkboxes. But it defaults to displaying the value returned by toString() for types it does not specifically handle. You have to provide your own TableCellRenderer implementation if you want to display buttons in a JTable. The TableCellRenderer interface contains only one method, getTableCellRendererComponent(...), which returns a java.awt.Component that knows how to draw the contents of a specific cell. Usually, getTableCellRendererComponent() will return the same component for every cell of a column, to avoid the unnecessary use of extra memory. But when the contents of a cell is itself a component, it is all right to return that component as the renderer. Therefore, the first step towards having JButtons display correctly in a JTable is to create a TableCellRenderer implementation that returns the JButton contained in the cell being rendered. In the accompanying code listing, JTableButtonRenderer demonstrates how to do this. Even after creating a custom TableCellRenderer, you're still not done. The TableModel associated with a given JTable does not only keep track of the contents of each cell, but it also keeps track of the class of data stored in each column. DefaultTableModel is designed to work with DefaultTableCellRenderer and will return java.lang.String.class for columns containing data types that it does not specifically handle. The exact method that does this is getColumnClass(int column). Your second step is to create a TableModel implementation that returns JButton.class for cells that contain JButtons. JTableButtonModel shows one way to do this. It just returns the result of getClass() for each piece of cell data. At this point, you're almost done, but not quite. What's the use of putting a JButton in a JTable if you can't press the darn thing? By default, JTable will not forward mouse events to components contained in its cells. If you want to be able to press the buttons you add to JTable, you have to create your own MouseListener that forwards events to the JButton cells. JTableButtonMouseListener demonstrates how you could do this.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值