如何使用自定义 JTable 单元格编辑器和单元格渲染器

Posted

技术标签:

【中文标题】如何使用自定义 JTable 单元格编辑器和单元格渲染器【英文标题】:How to use custom JTable cell editor and cell renderer 【发布时间】:2012-08-05 04:41:06 【问题描述】:

我创建了一个带有自定义表格渲染和自定义单元格编辑器的 JTable,它在图像中给出了结果

我使用扩展 JPanel 的单独类创建了第一个表格单元格中显示的面板。并将表值添加为,

        tbl.setCellEditor(new customCell());
        tbl.getColumnModel().getColumn(0).setCellRenderer(new customCell());

        DefaultTableModel dtm = (DefaultTableModel) tbl.getModel();

        Vector v = new Vector();
        v.add(new Panel());
        v.add("Test");
        dtm.addRow(v);

        v.clear();
        v.add(new Panel());
        v.add("Test 2");
        dtm.addRow(v);

这是我创建此表的表自定义类,

class customCell extends DefaultTableModel implements TableCellRenderer, TableCellEditor 

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
            Panel p = new Panel();            
            table.setRowHeight(row, p.getHeight());
            return p;
        

        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 

            return new Panel();
        

        public Object getCellEditorValue() 
            return "";
        

        public boolean isCellEditable(EventObject anEvent) 
            throw new UnsupportedOperationException("Not supported yet.");
        

        public boolean shouldSelectCell(EventObject anEvent) 
            return true;
        

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) 
            return true;
        

        public boolean stopCellEditing() 
            return true;
        

        public void cancelCellEditing() 
            throw new UnsupportedOperationException("Not supported yet.");
        

        public void addCellEditorListener(CellEditorListener l) 
            throw new UnsupportedOperationException("Not supported yet.");
        

        public void removeCellEditorListener(CellEditorListener l) 
            throw new UnsupportedOperationException("Not supported yet.");
        
    

我的问题是我认为面板按预期显示我无法在文本字段中输入或更改复选框或单击按钮。请告诉我如何解决这个问题。

【问题讨论】:

【参考方案1】:

我强烈建议重用默认表格渲染器和编辑器中提供的功能,因为您的代码有很多问题

    请拆分您的编辑器、渲染器和表格模型。让他们都在同一个班级很奇怪 对于您的渲染器,不要每次都创建 Component 的新实例。相反,重用相同的组件,只需在 getTableCellRendererComponent 方法中修改 Component 编辑器Component 也是如此 扩展默认编辑器,而不是使用 UnsupportedOperationExceptions 或仅返回空的 Strings 来实现方法

为了支持我的第四点,引用Editors part in the JTable tutorial:

如果您想指定文本字段、复选框或组合框以外的编辑器怎么办?由于 DefaultCellEditor 不支持其他类型的组件,您必须多做一些工作。您需要创建一个实现 TableCellEditor 接口的类。 AbstractCellEditor 类是一个很好的超类。它实现了 TableCellEditor 的超接口 CellEditor,省去了实现单元格编辑器所需的事件触发代码的麻烦。

您的单元格编辑器类至少需要定义两个方法——getCellEditorValue 和getTableCellEditorComponent。 CellEditor 所需的 getCellEditorValue 方法返回单元格的当前值。 TableCellEditor 所需的 getTableCellEditorComponent 方法应该配置并返回您要用作编辑器的组件。

正如那里清楚解释的那样,您必须实现事件触发代码:

为您省去实现单元格编辑器所需的事件触发代码的麻烦。

你显然忽略了。因此我建议从AbstractCellEditor 开始,而不是从头开始实现接口

【讨论】:

【参考方案2】:

必须为已经可见的JPanel 添加正确的LayoutManagerEditable/non_Editable 属性

尽情享受

import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;

public class PanelInTable 

    private JFrame frame;
    private JTable compTable = null;
    private PanelTableModel compModel = null;
    private JButton addButton = null;

    public static void main(String args[]) 
        try 
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
         catch (Exception fail) 
        
        SwingUtilities.invokeLater(() -> 
            new PanelInTable().makeUI();
        );
    

    public void makeUI() 
        compTable = CreateCompTable();
        JScrollPane CompTableScrollpane = new JScrollPane(compTable, 
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        JPanel bottomPanel = CreateBottomPanel();
        frame = new JFrame("Comp Table Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(CompTableScrollpane, BorderLayout.CENTER);
        frame.add(bottomPanel, BorderLayout.SOUTH);
        frame.setPreferredSize(new Dimension(800, 400));
        frame.setLocation(150, 150);
        frame.pack();
        frame.setVisible(true);
    

    public JTable CreateCompTable() 
        compModel = new PanelTableModel();
        compModel.addRow();
        JTable table = new JTable(compModel);
        table.setRowHeight(new CompCellPanel().getPreferredSize().height);
        table.setTableHeader(null);
        PanelCellEditorRenderer PanelCellEditorRenderer = new PanelCellEditorRenderer();
        table.setDefaultRenderer(Object.class, PanelCellEditorRenderer);
        table.setDefaultEditor(Object.class, PanelCellEditorRenderer);
        return table;
    

    public JPanel CreateBottomPanel() 
        addButton = new JButton("Add Comp");
        addButton.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent ae) 
                Object source = ae.getSource();
                if (source == addButton) 
                    compModel.addRow();
                
            
        );
        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(addButton);
        return panel;
    


class PanelCellEditorRenderer extends AbstractCellEditor implements 
        TableCellRenderer, TableCellEditor 

    private static final long serialVersionUID = 1L;
    private CompCellPanel renderer = new CompCellPanel();
    private CompCellPanel editor = new CompCellPanel();

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, 
            boolean isSelected, boolean hasFocus, int row, int column) 
        renderer.setComp((Comp) value);
        return renderer;
    

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, 
            boolean isSelected, int row, int column) 
        editor.setComp((Comp) value);
        return editor;
    

    @Override
    public Object getCellEditorValue() 
        return editor.getComp();
    

    @Override
    public boolean isCellEditable(EventObject anEvent) 
        return true;
    

    @Override
    public boolean shouldSelectCell(EventObject anEvent) 
        return false;
    


class PanelTableModel extends DefaultTableModel 

    private static final long serialVersionUID = 1L;

    @Override
    public int getColumnCount() 
        return 1;
    

    public void addRow() 
        super.addRow(new Object[]new Comp(0, 0, "", ""));
    


class Comp 

    public int type;
    public int relation;
    public String lower;
    public String upper;

    public Comp(int type, int relation, String lower, String upper) 
        this.type = type;
        this.relation = relation;
        this.lower = lower;
        this.upper = upper;
    


class CompCellPanel extends JPanel 

    private static final long serialVersionUID = 1L;
    private JLabel labelWith = new JLabel("With ");
    private JComboBox typeCombo = new JComboBox(new Object[]
    "height", "length", "volume");
    private JComboBox relationCombo = new JComboBox(new Object[]
    "above", "below", "between");
    private JTextField lowerField = new JTextField();
    private JLabel labelAnd = new JLabel(" and ");
    private JTextField upperField = new JTextField();
    private JButton removeButton = new JButton("remove");

   public CompCellPanel() 
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        relationCombo.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                enableUpper(relationCombo.getSelectedIndex() == 2);
            
        );
        enableUpper(false);
        removeButton.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                JTable table = (JTable) SwingUtilities.getAncestorOfClass(
                        JTable.class, (Component) e.getSource());
                int row = table.getEditingRow();
                table.getCellEditor().stopCellEditing();
                ((DefaultTableModel) table.getModel()).removeRow(row);
            
        );
        add(labelWith);
        add(typeCombo);
        add(relationCombo);
        add(lowerField);
        add(labelAnd);
        add(upperField);
        add(Box.createHorizontalStrut(100));
        add(removeButton);
    

    private void enableUpper(boolean enable) 
        labelAnd.setEnabled(enable);
        upperField.setEnabled(enable);
    

    public void setComp(Comp Comp) 
        typeCombo.setSelectedIndex(Comp.type);
        relationCombo.setSelectedIndex(Comp.relation);
        lowerField.setText(Comp.lower);
        upperField.setText(Comp.upper);
        enableUpper(Comp.relation == 2);
    

    public Comp getComp() 
        return new Comp(typeCombo.getSelectedIndex(), 
                relationCombo.getSelectedIndex(), 
                lowerField.getText(), upperField.getText());
    

【讨论】:

停止编辑属于编辑器,而不是面板。此外,从外部 actionListener 弄乱模型是……有争议的 ;-) 感谢您的精彩捕捉,顺便说一句,您的诚实修改了此代码超过 3 次,我尝试移动并使用 Rob 制作的 JTable 中的 Action(我认为没有比这更好、更免费、更简单的了),没有任何更改和事件被触发, 你为什么要扩展 AbstractCellEditor @Radu Simionescu 因为....... 冰熊??? :-),我认为 SSCCE forn 中的代码示例最简单、紧凑,坚持公共论坛 请使用小写的变量名,这很混乱。

以上是关于如何使用自定义 JTable 单元格编辑器和单元格渲染器的主要内容,如果未能解决你的问题,请参考以下文章

Java Swing Jtable 单元格不可编辑

如何将JComboBox添加到JTable单元格?

Java JTable改变单元格颜色

如何使 JTable 单元格不可编辑但应该能够选择和复制当前单元格中的值

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

如何在 JTable 中编辑行