Java 意外的jtable自定义呈现程序行为

Java 意外的jtable自定义呈现程序行为,java,swing,jtable,Java,Swing,Jtable,我的目标是在JavaSwing中制作一个基本的像素艺术应用程序(我知道这远远不够理想,我们必须为一个类使用Swing做一些事情,我觉得这听起来很有趣) 其思想是将JTable中任何选定单元格的颜色更改为JComboBox中选定的颜色 以下是单击高亮显示的单元格(9,7)后的当前外观: 在其他地方单击(如图所示的(0,6))后,它倾向于填充两个空间之间的空间,以及行的其余部分 这当然不理想-每次单击只需一个单元格即可更改颜色。我是自定义JTable渲染的新手,因此我附加了必要的代码,希望有人能

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

其思想是将JTable中任何选定单元格的颜色更改为JComboBox中选定的颜色

以下是单击高亮显示的单元格(9,7)后的当前外观:

在其他地方单击(如图所示的(0,6))后,它倾向于填充两个空间之间的空间,以及行的其余部分

这当然不理想-每次单击只需一个单元格即可更改颜色。我是自定义JTable渲染的新手,因此我附加了必要的代码,希望有人能帮助我发现错误。当我在CustomModel类中创建JTable时,感兴趣的区域朝向底部

//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;
    }
}
我很感激任何提示,我一直在研究如何解决这个问题。

请看一看,并了解有关渲染器和编辑器实际工作方式的更多详细信息

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

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

也许像


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

您应该将颜色值存储在TableModel中,然后您的渲染器应该渲染单元格的值。我看不出任何使用反射的理由。另外,我不明白间隔选择应该如何工作。当你点击一个单元格时,你希望其他哪些单元格是彩色的?如果我选择了“红色”,我只希望我点击的单元格变成红色,并一直保持红色,直到再次点击并选择另一种颜色为止。但是当我点击一个单元格时,它正在改变整行的颜色。你必须通过单元格渲染器来做吗?@user1803551我不知道你的意思,它对我来说似乎很好。我自己也被它绊倒了:{顺便说一句,你用什么来创建
gif
?会派上用场:)哇,太漂亮了-非常感谢!
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;
        }

    }
}