切换JTable中按钮的颜色

时间:2016-01-06 14:44:50

标签: java swing button colors jtable

我正在尝试在JTable的单元格内部实现单击颜色更改按钮。我已经确实已经改变颜色onClick但是我没有得到的是,背景颜色如何保持按钮切换到的颜色。无论何时我通过单击另一个单元格或在表格内部松开焦点,按钮再次变为白色。我认为它与渲染器有关,也许你可以支持我。

public abstract class DisplayItem : INotifyPropertyChanged
{
    private string _path;
    public virtual string Path
    {
        get { return _path; }
        set
        {
            _path = value;
            OnPropertyChanged();
        }
    }

    private long _size;
    public long Size {
        get { return _size; }
        set
        {
            _size = value;
            OnPropertyChanged();
        } 
    }

    private bool _checked;
    public bool Checked
    {
        get { return _checked; }
        set
        {
            _checked = value;
            OnPropertyChanged();
        }
    }

    public override string ToString()
    {
        return Path;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

ButtonEditor.java:

    signalTable = new JTable();
    signalTable.setModel(new DefaultTableModel(
        new Object[][] {
            {"AAA", "A_SIGNAL", null, null, null, null, null, null, null, null, "Example", Boolean.TRUE},
        },
        new String[] {
            "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", ""
        }
    ) {
        Class[] columnTypes = new Class[] {
            String.class, String.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, String.class, Boolean.class
        };
        public Class getColumnClass(int columnIndex) {
            return columnTypes[columnIndex];
        }
    });
    TableColorRenderer renderer = new TableColorRenderer();
    signalTable.getColumn("0").setCellRenderer(renderer);
    signalTable.getColumn("1").setCellRenderer(renderer);
    signalTable.getColumn("2").setCellRenderer(renderer);
    signalTable.getColumn("3").setCellRenderer(renderer);
    signalTable.getColumn("4").setCellRenderer(renderer);
    signalTable.getColumn("5").setCellRenderer(renderer);
    signalTable.getColumn("6").setCellRenderer(renderer);
    signalTable.getColumn("7").setCellRenderer(renderer);
    signalTable.getColumn("0").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("1").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("2").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("3").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("4").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("5").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("6").setCellEditor(new ButtonEditor(new JCheckBox()));
    signalTable.getColumn("7").setCellEditor(new ButtonEditor(new JCheckBox()));

TableColorRenderer.java:

public class ButtonEditor extends DefaultCellEditor
{
    protected JButton button;

    public ButtonEditor(JCheckBox checkBox) 
    {
        super(checkBox);
        button = new JButton();
        button.setOpaque(true);
        button.addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent e)
            {
                button.setBackground(Color.GREEN);
                button.repaint();
            }
        });
    }

    public Component getTableCellEditorComponent(JTable table, Object value,
        boolean isSelected, int row, int column) 
    {
        return button;
    }

}

When clicked on invisible Button

After clicked in another row

2 个答案:

答案 0 :(得分:2)

你显然误解了编辑器和渲染器的角色。编辑器允许用户编辑单元格的状态,渲染器渲染单元格的状态。

他们通过使用TableModel来做到这一点。首先查看Concepts: Editors and RenderersUsing Other Editors了解更多详情。

从你做错的事情开始......

signalTable.setModel(new DefaultTableModel(
    new Object[][] {
        {"AAA", "A_SIGNAL", null, null, null, null, null, null, null, null, "Example", Boolean.TRUE},
    },
    new String[] {
        "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", ""
    }
) {
    Class[] columnTypes = new Class[] {
        String.class, String.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, String.class, Boolean.class
    };
    public Class getColumnClass(int columnIndex) {
        return columnTypes[columnIndex];
    }
});

“颜色”单元格的单元格值应为truefalse(它们可以是您想要的任何其他“开启”/“关闭”值,只要编辑器和渲染器知道如何处理它们,但是对于这个例子,我正在使用boolean s)

这些单元格的columnType也应为Boolean.class

signalTable.setModel(new DefaultTableModel(
        new Object[][]{
            {"AAA", "A_SIGNAL", false, false, false, false, false, false, false, false, "Example", Boolean.TRUE},},
        new String[]{
            "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", ""
        }
) {
    Class[] columnTypes = new Class[]{
        String.class, String.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, String.class, Boolean.class
    };

    public Class getColumnClass(int columnIndex) {
        return columnTypes[columnIndex];
    }
});

所以,现在,如果你什么也没做,你会在那些单元格中有JCheckBox,但那不是我们想要的。

public class ButtonEditor extends DefaultCellEditor
{
    protected JButton button;

    public ButtonEditor(JCheckBox checkBox) 
    {
        super(checkBox);
        button = new JButton();
        button.setOpaque(true);
        button.addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent e)
            {
                button.setBackground(Color.GREEN);
                button.repaint();
            }
        });
    }

    public Component getTableCellEditorComponent(JTable table, Object value,
        boolean isSelected, int row, int column) 
    {
        return button;
    }

}

在这里,您忽略了传递给编辑器并创建自己的JCheckBox,但这有两个问题。 DefaultCellEditorJCheckBox派生单元格值,而不是其他某些状态(因此它总是false),您永远不会将button配置为代表当前状态请求时的单元格。

因为我不想处理其他组件,所以我会做一些不同的事情。

public class ButtonEditor extends AbstractCellEditor implements TableCellEditor {

    private JLabel editor;

    public ButtonEditor() {
        editor = new JLabel();
        editor.setBackground(Color.GREEN);

        editor.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                editor.setOpaque(!editor.isOpaque());
                stopCellEditing();
            }
        });
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        if (value instanceof Boolean) {
            boolean result = (boolean) value;
            editor.setOpaque(!result);
        }
        return editor;
    }

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

    @Override
    public boolean isCellEditable(EventObject e) {
        return true;
    }

}

这只是JLabel,点击后会切换它的不透明状态。我们还使用此状态来确定编辑器“停止”时的单元格值

public class TableColorRenderer extends JLabel implements TableCellRenderer
{
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    {
        return this;
    }
}

嗯,坦率地说,这有点无用,它从来没有对细胞的价值做任何事情

public class TableColorRenderer extends JLabel implements TableCellRenderer {

    public TableColorRenderer() {
        setBackground(Color.GREEN);
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        if (value instanceof Boolean) {
            boolean result = (boolean) value;
            setOpaque(result);
        } else {
            setOpaque(false);
        }
        return this;
    }
}

再次,非常简单。我们检查单元格的值(传递给我们)并相应地更改opaque状态

因为没有人相信我,一个可运行的例子

Editor

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class Example {

    public static void main(String[] args) {
        new Example();
    }

    public Example() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private final JTable signalTable;

        public TestPane() {
            signalTable = new JTable();
    signalTable.setModel(new DefaultTableModel(
            new Object[][]{
                {"AAA", "A_SIGNAL", false, false, false, false, false, false, false, false, "Example", Boolean.TRUE},},
            new String[]{
                "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", ""
            }
    ) {
        Class[] columnTypes = new Class[]{
            String.class, String.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, String.class, Boolean.class
        };

        public Class getColumnClass(int columnIndex) {
            return columnTypes[columnIndex];
        }
    });
            TableColorRenderer renderer = new TableColorRenderer();
            signalTable.getColumn("0").setCellRenderer(renderer);
            signalTable.getColumn("1").setCellRenderer(renderer);
            signalTable.getColumn("2").setCellRenderer(renderer);
            signalTable.getColumn("3").setCellRenderer(renderer);
            signalTable.getColumn("4").setCellRenderer(renderer);
            signalTable.getColumn("5").setCellRenderer(renderer);
            signalTable.getColumn("6").setCellRenderer(renderer);
            signalTable.getColumn("7").setCellRenderer(renderer);
            signalTable.getColumn("0").setCellEditor(new ButtonEditor());
            signalTable.getColumn("1").setCellEditor(new ButtonEditor());
            signalTable.getColumn("2").setCellEditor(new ButtonEditor());
            signalTable.getColumn("3").setCellEditor(new ButtonEditor());
            signalTable.getColumn("4").setCellEditor(new ButtonEditor());
            signalTable.getColumn("5").setCellEditor(new ButtonEditor());
            signalTable.getColumn("6").setCellEditor(new ButtonEditor());
            signalTable.getColumn("7").setCellEditor(new ButtonEditor());

            setLayout(new BorderLayout());
            add(new JScrollPane(signalTable));
        }

    }

    public class ButtonEditor extends AbstractCellEditor implements TableCellEditor {

        private JLabel editor;

        public ButtonEditor() {
            editor = new JLabel();
            editor.setBackground(Color.GREEN);

            editor.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    editor.setOpaque(!editor.isOpaque());
                    stopCellEditing();
                }
            });
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            if (value instanceof Boolean) {
                boolean result = (boolean) value;
                editor.setOpaque(!result);
            }
            return editor;
        }

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

        @Override
        public boolean isCellEditable(EventObject e) {
            return true;
        }

    }

    public class TableColorRenderer extends JLabel implements TableCellRenderer {

        public TableColorRenderer() {
            setBackground(Color.GREEN);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (value instanceof Boolean) {
                boolean result = (boolean) value;
                setOpaque(result);
            }
            return this;
        }
    }
}

答案 1 :(得分:1)

在下面找到一个在单元格中使用JButton的小型演示应用程序。按钮文本用于演示MadProgrammer解释的逻辑。按钮文本为edit btn. resp。 render btn.。因此可以看到实际显示的按钮。单击单元格时会显示编辑按钮。

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import static javax.swing.GroupLayout.PREFERRED_SIZE;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.table.DefaultTableModel;

public class FrameDemo extends JFrame {

    public FrameDemo() {
        initComponents();
    }

    private void initComponents() {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        JTable signalTable = new JTable();
        signalTable.setModel(new DefaultTableModel(
                new Object[][]{
                    {"AAA", "A_SIGNAL", FALSE, FALSE, FALSE, TRUE},
                    {"BBB", "B_SIGNAL", FALSE, FALSE, FALSE, TRUE},
                    {"CCC", "C_SIGNAL", FALSE, FALSE, FALSE, TRUE},
                    {"DDD", "C_SIGNAL", FALSE, FALSE, FALSE, TRUE}
                },
                new String[]{"ID", "Message Identifier", "0", "1", "2", ""}
        ));

        CellButton cellButton = new CellButton();
        signalTable.getColumn("0").setCellRenderer(cellButton);
        signalTable.getColumn("0").setCellEditor(cellButton);
        signalTable.getColumn("1").setCellRenderer(cellButton);
        signalTable.getColumn("1").setCellEditor(cellButton);
        signalTable.getColumn("2").setCellRenderer(cellButton);
        signalTable.getColumn("2").setCellEditor(cellButton);

        JScrollPane scrollPane = new javax.swing.JScrollPane();
        scrollPane.setViewportView(signalTable);

        GroupLayout layout = new GroupLayout(getContentPane());

        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(Alignment.LEADING)
                .addGroup(Alignment.TRAILING, layout.createSequentialGroup()
                        .addContainerGap(10, Short.MAX_VALUE)
                        .addComponent(scrollPane, PREFERRED_SIZE, 700, 
                            PREFERRED_SIZE)
                        .addContainerGap())
        );
        layout.setVerticalGroup(
                layout.createParallelGroup(Alignment.LEADING)
                .addGroup(Alignment.TRAILING, layout.createSequentialGroup()
                        .addContainerGap(10, Short.MAX_VALUE)
                        .addComponent(scrollPane, PREFERRED_SIZE, 275, 
                            PREFERRED_SIZE)
                        .addContainerGap())
        );
        pack();
    }

    public static void main(String args[]) {
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                try {
                    UIManager.setLookAndFeel(info.getClassName());
                } catch (Exception ex) {
                    System.err.println("use default L&F");
                }
                break;
            }
        }

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new FrameDemo().setVisible(true);
            }
        });
    }
}

单元格编辑器和渲染器的类。

import java.awt.Color;
import static java.awt.Color.BLACK;
import static java.awt.Color.GREEN;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class CellButton extends AbstractCellEditor
        implements TableCellEditor, TableCellRenderer {

    private final JButton editButton = new JButton("edit btn.");
    private final JButton renderButton = new JButton("render btn.");
    private final Border focusBorder = BorderFactory.createLineBorder(BLACK);
    private final Border defaultBorder;
    private final Color inactiveColor;
    private Boolean state = FALSE;

    public CellButton() {
        defaultBorder = renderButton.getBorder();
        inactiveColor = renderButton.getBackground();
        editButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                cancelCellEditing();
            }
        });

        editButton.addActionListener((e) -> {stopCellEditing();});
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int column) {
        state = FALSE.equals(value);
        editButton.setBackground(state ? GREEN : inactiveColor);
        table.setValueAt(state, row, column);
        return editButton;
    }

    @Override
    public Object getCellEditorValue() {
        return state;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        renderButton.setBorder(hasFocus ? focusBorder : defaultBorder);
        renderButton.setBackground(TRUE.equals(value) ? GREEN : inactiveColor);
        return renderButton;
    }
}

可以使用鼠标或键盘切换按钮。

enter image description here