Question on jtable cell editors in swing

好久不见. 提交于 2020-01-11 11:13:13

问题


I want to implement a component that serves as a list of options, that a user can choose to select or not.
Visually I thought that it would be best presented in a UI (if there is a better approach please tell me) as follows:

Anyway, I thought that this could be implemented via a JTable (single column) and using a JCheckBox as a cell editor.
I tried it but did not work.
Example of code:

public class ListRenderer extends JFrame {

    JCheckBox checkbox = new JCheckBox("Test");
    DefaultCellEditor dce1 = new DefaultCellEditor(checkbox);

    public ListRenderer(){          

        Object[][] data =  {   {"Test"} };
        String[] columnNames = {"Options"};

        DefaultTableModel model = new DefaultTableModel(data,columnNames);

        JTable table = new JTable(model){

            public TableCellEditor getCellEditor(int row, int column)            
            {               
                return dce1;                
            }

        };
        JScrollPane scrollPane = new JScrollPane( table );        
        getContentPane().add( scrollPane );
    }

What happens is that when the frame appears I see the "Test" in the table but it does not appear like a checkbox (as in the example image).
If I click on the cell, it turns into a checkbox (click button on the left and not right) but the text changes to show either true or false! It does not keep showing "Test"
More over the text depends on whether I keep pressing on the cell or not.
If I change the JCheckBox to a JComboBox the behavior is correct as far as I can tell.
Can anyone please tell me what am I doing wrong here?
Thanks!


回答1:


To be rendered as a JCheckBox by default, the table's model must return Boolean.class as the type for that column. If you are using DefaultTableModel, you will have to override getColumnClass() accordingly. Here's a related example.

Addendum: Note in the example that the editor's private instance of ValueRenderer can apply ItemEvent directly, instead of via setValueAt().

Addendum: The example has been updated to reflect the correct model-view workflow.

setValueAt() is called anyway. Verified it via debugging

If you step into setValueAt(), you'll see that "This empty implementation is provided so users don't have to implement this method if their data model is not editable."




回答2:


here you can find answer why (JButtons JComponents) JCheckBox and JRadioButton ... are little bit different for Rendering in the TableCell as another JComponents (and you have to play with JTable row Selection because I changed Opacity)

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

public class CheckboxInCellTest {

    private String[] columnNames = {"Boolean(Default)", "Boolean"};
    private Object[][] data = {{false, true}, {true, false}, {false, true}};
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };

    public JComponent makeUI() {
        JTable table = new JTable(model);
        table.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                JTable t = (JTable) e.getComponent();
                Point pt = e.getPoint();
                int row = t.rowAtPoint(pt), col = t.columnAtPoint(pt);
                if (t.convertColumnIndexToModel(col) == 1) {
                    t.getCellEditor(row, col).stopCellEditing();
                }
            }
        });
        table.setRowHeight(20);
        CheckBoxEditorRenderer1 cer = new CheckBoxEditorRenderer1();
        table.getColumnModel().getColumn(1).setCellRenderer(cer);
        table.getColumnModel().getColumn(1).setCellEditor(cer);
        JPanel p = new JPanel(new BorderLayout());
        p.add(new JScrollPane(table));
        return p;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new CheckboxInCellTest().makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class CheckBoxPanel1 extends JPanel {

    private static final long serialVersionUID = 1L;
    public final JCheckBox button = new JCheckBox();

    CheckBoxPanel1() {
        super(new GridBagLayout());
        add(button);
        button.setOpaque(false);
        setOpaque(false);
    }
}

class CheckBoxEditorRenderer1 extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {

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

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean is, boolean hf, int row, int column) {
        renderer.button.setSelected(Boolean.TRUE.equals(value));
        renderer.button.setOpaque(is);
        return renderer;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        editor.button.setSelected(Boolean.TRUE.equals(value));
        renderer.button.setOpaque(isSelected);
        return editor;
    }

    @Override
    public Object getCellEditorValue() {
        return editor.button.isSelected();
    }
}

and with JButton in the TableCell ... with Nimbus L&F (required Java > 1.6.17 ??? now I have xxx.25)

import com.sun.java.swing.Painter;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import sun.swing.table.DefaultTableCellHeaderRenderer;

public class TableButtonTest extends JFrame {

    private static final long serialVersionUID = 1L;

    public TableButtonTest() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTable table = new JTable(new TestModel());
        table.getTableHeader().setReorderingAllowed(false);
        table.setRowHeight(20);
        table.getColumnModel().getColumn(1).setPreferredWidth(3);
        table.getColumnModel().getColumn(2).setPreferredWidth(3);
        table.getTableHeader().setDefaultRenderer(new WrappingRenderer(table.getTableHeader()));
        this.add(new JScrollPane(table));
        Action increase = new AbstractAction("+") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) e.getSource();
                int row = Integer.valueOf(e.getActionCommand());
                TestModel model = (TestModel) table.getModel();
                model.increment(row, 0);
                //model.fireTableCellUpdated(row, 0);
            }
        };
        ButtonColumn inc = new ButtonColumn(table, increase, 1);
        Action decrease = new AbstractAction("-") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) e.getSource();
                int row = Integer.valueOf(e.getActionCommand());
                TestModel model = (TestModel) table.getModel();
                model.decrement(row, 0);
            }
        };
        ButtonColumn dec = new ButtonColumn(table, decrease, 2);
        JTableHeader tbh = table.getTableHeader();
        tbh.setOpaque(false);
        Painter painter = new com.sun.java.swing.Painter() {

            public void paint(Graphics2D g, Object o, int w, int h) {
            }
        };
        javax.swing.UIDefaults defaults = new javax.swing.UIDefaults();
        defaults.put("TableHeader:\"TableHeader.renderer\"[Pressed].backgroundPainter", painter);
        defaults.put("TableHeader:\"TableHeader.renderer\"[Pressed].backgroundPainter",
                defaults.get(("TableHeader:\"TableHeader.renderer\"[Pressed].backgroundPainter")));
        tbh.putClientProperty("Nimbus.Overrides", defaults);
        tbh.putClientProperty("Nimbus.State", "Pressed");
        tbh.putClientProperty("JTree.lineStyle", "Angled");
        setLocation(200, 200);
        pack();
    }

    private static class WrappingRenderer implements TableCellRenderer {

        private DefaultTableCellHeaderRenderer delegate;
        private JTableHeader header;

        public WrappingRenderer(JTableHeader header) {
            this.header = header;
            this.delegate = (DefaultTableCellHeaderRenderer) header.getDefaultRenderer();
            header.setDefaultRenderer(this);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component comp = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            TableColumn draggedColumn = table.getTableHeader().getDraggedColumn();
            if (isSelected) {
                comp.setBackground(table.getSelectionBackground());
            } else {
                comp.setBackground(table.getBackground());
            }

            if (draggedColumn != null) {
                if (table.convertColumnIndexToModel(column) == draggedColumn.getModelIndex()) {
                    setNimbusState("Pressed");
                } else {
                    setNimbusState(null);
                }
            } else {
                setNimbusState(null);
            }
            // do similar for resizing column
            return comp;
        }

        public void setNimbusState(String state) {
            delegate.putClientProperty("Nimbus.State", state);
        }
    }

    public static void main(String[] args) {
        try {
            // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if (info.getName().equals("Nimbus")) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        new TableButtonTest().setVisible(true);
    }
}

class TestModel extends AbstractTableModel {

    private static final long serialVersionUID = 1L;
    private List<TestRecord> records = new LinkedList<TestRecord>();

    private static class TestRecord {

        private int val = 0;
    }

    public void increment(int row, int col) {
        records.get(row).val++;
        fireTableCellUpdated(row, col);
    }

    public void decrement(int row, int col) {
        records.get(row).val--;
        fireTableCellUpdated(row, col);
    }

    public TestModel() {
        records.add(new TestRecord());
        records.add(new TestRecord());
    }

    @Override
    public Class<?> getColumnClass(int col) {
        switch (col) {
            case 0:
                return Integer.class;
            case 1:
                return ButtonColumn.class;
            case 2:
                return Boolean.class;
            default:
                return String.class;
        }
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return true;
    }

    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public int getRowCount() {
        return records.size();
    }

    @Override
    public Object getValueAt(int row, int col) {
        if (col == 0) {
            return records.get(row).val;
        } else if (col == 1) {
            return "+";
        } else {
            return "-";
        }
    }
}


来源:https://stackoverflow.com/questions/6633437/question-on-jtable-cell-editors-in-swing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!