意外的jtable自定义渲染器行为

时间:2016-02-10 01:59:50

标签: java swing jtable

我的目标是在Java Swing中创建一个基本的像素艺术应用程序(我知道这远非理想,我们必须为一个类做一些Swing的事情,我觉得这听起来很有趣)。

我们的想法是,JTable中任何选定单元格的颜色都会更改为JComboBox中选择的颜色。

以下是在突出显示的单元格(9,7)上点击后的情况:

After one click at (9,7)

在其他地方点击后(例如显示在(0,6)处),它往往会填充两个空格之间的空间,以及其余的行。

After a second click at (0,6)

这当然不理想 - 我只希望一个单元格改变每次点击的颜色。我是自定义JTable渲染的新手,所以我附上了必要的代码,希望有人可以帮助我发现我的错误。当我创建JTable CustomModel类时,感兴趣的区域就在底部。

//Lots of importing

public class PixelArtistGUI extends JFrame {

String colors[] = { "Red", "Orange", "Yellow", "Green", "Blue", "Magenta", "Black", "White" };
JComboBox colorList = new JComboBox(colors);

public PixelArtistGUI() {
    setTitle("PixelArtist");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setResizable(false);
    this.setPreferredSize(new Dimension(400, 450));

    // Content Pane

    JPanel contentPane = new JPanel();
    setContentPane(contentPane);

    GridBagLayout gbl_contentPane = new GridBagLayout();
    gbl_contentPane.columnWidths = new int[] { 125, 125, 125 };
    gbl_contentPane.rowHeights = new int[] {360, 15};
    contentPane.setLayout(gbl_contentPane);

    JLabel colorSelect = new JLabel("Select Color:");
    colorSelect.setFont(new Font("Tahoma", Font.PLAIN, 18));
    colorSelect.setHorizontalAlignment(SwingConstants.CENTER);
    GridBagConstraints gbc_colorSelect = new GridBagConstraints();
    gbc_colorSelect.insets = new Insets(5, 0, 0, 0);
    gbc_colorSelect.gridx = 0;
    gbc_colorSelect.anchor = GridBagConstraints.SOUTH;
    gbc_colorSelect.fill = GridBagConstraints.BOTH;
    gbc_colorSelect.gridy = 1;
    contentPane.add(colorSelect, gbc_colorSelect);
    GridBagConstraints gbc_colorList = new GridBagConstraints();
    gbc_colorList.anchor = GridBagConstraints.SOUTH;
    gbc_colorList.fill = GridBagConstraints.BOTH;
    gbc_colorList.insets = new Insets(5, 0, 0, 0);
    gbc_colorList.gridx = 1;
    gbc_colorList.gridy = 1;
    contentPane.add(colorList, gbc_colorList);

    JButton screenshotButton = new JButton("Save Screenshot");
    GridBagConstraints gbc_screenshotButton = new GridBagConstraints();
    gbc_screenshotButton.anchor = GridBagConstraints.SOUTH;
    gbc_screenshotButton.fill = GridBagConstraints.BOTH;
    gbc_screenshotButton.insets = new Insets(5, 0, 0, 0);
    gbc_screenshotButton.gridx = 2;
    gbc_screenshotButton.gridy = 1;
    contentPane.add(screenshotButton, gbc_screenshotButton);

    String[] colHeadings = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };
    int numRows = 16;
    PixelModel model = new PixelModel(numRows, colHeadings.length);
    model.setColumnIdentifiers(colHeadings);

    JTable table_1 = new JTable(model);
    table_1.setBorder(new LineBorder(new Color(0, 0, 0)));
    table_1.setRowSelectionAllowed(false);
    table_1.setDefaultRenderer(Object.class, new CustomModel());

    GridBagConstraints gbc_table_1 = new GridBagConstraints();
    gbc_table_1.gridwidth = 3;
    gbc_table_1.fill = GridBagConstraints.BOTH;
    gbc_table_1.gridx = 0;
    gbc_table_1.gridy = 0;
    contentPane.add(table_1, gbc_table_1);
    table_1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    table_1.setCellSelectionEnabled(true);
    table_1.setRowHeight(23);

    this.pack();
}

// Custom table renderer to change cell colors
public class CustomModel extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column) {
        JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
                column);
        Color c;
        try {
            String cString = colorList.getSelectedItem().toString().toLowerCase();
            Field field = Class.forName("java.awt.Color").getField(cString);
            c = (Color) field.get(null);
        } catch (Exception e) {
            c = null;
        }

        if (isSelected)
            label.setBackground(c);
        return label;
    }
}

// Custom table model to make the cells selectable but not editable
public class PixelModel extends DefaultTableModel {

    PixelModel(int numRows, int numColumns) {
        super(numRows, numColumns);
    }

    public boolean isCellEditable(int row, int column) {
        return false;
    }
}

我感谢任何提示,我坚持如何解决这个问题。

1 个答案:

答案 0 :(得分:3)

请查看Concepts: Editors and RenderersWriting a Custom Cell RendererUsing Other Editors,详细了解渲染器和编辑器的实际工作方式。

每次调用getTableCellRendererComponent时,都需要根据单元格的值和状态完全配置渲染器。所以基本上,你正在做的只是简单地设置一次背景颜色,而不是为任何其他条件更改它,这意味着当任何其他单元格被绘制时(无论出于何种原因),它仍然使用相同的背景颜色。

相反,您应该使用TableModel中存储的值来决定单元格应该绘制的内容。要做到这一点,你可能需要一个简单的CellEditor,它可以简单地返回当前选择的颜色

也许像......

Pixel

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;

public class PixelArtistGUI extends JFrame {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                PixelArtistGUI frame = new PixelArtistGUI();
                frame.setVisible(true);
            }
        });
    }

    String colors[] = {"Red", "Orange", "Yellow", "Green", "Blue", "Magenta", "Black", "White"};
    JComboBox colorList = new JComboBox(colors);

    public PixelArtistGUI() {
        setTitle("PixelArtist");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        this.setPreferredSize(new Dimension(400, 450));

        // Content Pane
        JPanel contentPane = new JPanel();
        setContentPane(contentPane);

        GridBagLayout gbl_contentPane = new GridBagLayout();
        gbl_contentPane.columnWidths = new int[]{125, 125, 125};
        gbl_contentPane.rowHeights = new int[]{360, 15};
        contentPane.setLayout(gbl_contentPane);

        JLabel colorSelect = new JLabel("Select Color:");
        colorSelect.setFont(new Font("Tahoma", Font.PLAIN, 18));
        colorSelect.setHorizontalAlignment(SwingConstants.CENTER);
        GridBagConstraints gbc_colorSelect = new GridBagConstraints();
        gbc_colorSelect.insets = new Insets(5, 0, 0, 0);
        gbc_colorSelect.gridx = 0;
        gbc_colorSelect.anchor = GridBagConstraints.SOUTH;
        gbc_colorSelect.fill = GridBagConstraints.BOTH;
        gbc_colorSelect.gridy = 1;
        contentPane.add(colorSelect, gbc_colorSelect);
        GridBagConstraints gbc_colorList = new GridBagConstraints();
        gbc_colorList.anchor = GridBagConstraints.SOUTH;
        gbc_colorList.fill = GridBagConstraints.BOTH;
        gbc_colorList.insets = new Insets(5, 0, 0, 0);
        gbc_colorList.gridx = 1;
        gbc_colorList.gridy = 1;
        contentPane.add(colorList, gbc_colorList);

        JButton screenshotButton = new JButton("Save Screenshot");
        GridBagConstraints gbc_screenshotButton = new GridBagConstraints();
        gbc_screenshotButton.anchor = GridBagConstraints.SOUTH;
        gbc_screenshotButton.fill = GridBagConstraints.BOTH;
        gbc_screenshotButton.insets = new Insets(5, 0, 0, 0);
        gbc_screenshotButton.gridx = 2;
        gbc_screenshotButton.gridy = 1;
        contentPane.add(screenshotButton, gbc_screenshotButton);

        String[] colHeadings = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
        int numRows = 16;
        PixelModel model = new PixelModel(numRows, colHeadings.length);
        model.setColumnIdentifiers(colHeadings);

        JTable table_1 = new JTable(model);
        table_1.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                TableCellEditor editor = table_1.getCellEditor();
                if (editor != null) {
                    if (editor.stopCellEditing()) {
                        editor.cancelCellEditing();
                    }
                }
            }
        });
        table_1.setBorder(new LineBorder(new Color(0, 0, 0)));
        table_1.setRowSelectionAllowed(false);
        table_1.setDefaultRenderer(Object.class, new CustomRenderer());
        table_1.setDefaultEditor(Object.class, new CustomEditor());

        GridBagConstraints gbc_table_1 = new GridBagConstraints();
        gbc_table_1.gridwidth = 3;
        gbc_table_1.fill = GridBagConstraints.BOTH;
        gbc_table_1.gridx = 0;
        gbc_table_1.gridy = 0;
        contentPane.add(table_1, gbc_table_1);
        table_1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        table_1.setCellSelectionEnabled(true);
        table_1.setRowHeight(23);

        this.pack();
    }

    public class CustomRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            super.getTableCellRendererComponent(table, null, false, hasFocus, row, column);
            if (value != null && value instanceof Color) {
                setBackground((Color) value);
            } else {
                setBackground(null);
            }
            return this;
        }
    }

    public class CustomEditor extends AbstractCellEditor implements TableCellEditor {

        private JPanel panel;

        public CustomEditor() {
            this.panel = new JPanel();
        }

        @Override
        public Object getCellEditorValue() {
            Color c = null;
            try {
                String cString = colorList.getSelectedItem().toString().toLowerCase();
                Field field = Class.forName("java.awt.Color").getField(cString);
                c = (Color) field.get(null);
            } catch (Exception e) {
                c = null;
            }
            return c;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            panel.setBackground((Color) getCellEditorValue());
            return panel;
        }

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

    }

    // Custom table model to make the cells selectable but not editable
    public class PixelModel extends DefaultTableModel {

        PixelModel(int numRows, int numColumns) {
            super(numRows, numColumns);
        }

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

    }
}

现在,在有人跳我之前。我会用JComboBox填充Color并使用自定义ListCellRenderer来显示它。