我的目标是在Java Swing中创建一个基本的像素艺术应用程序(我知道这远非理想,我们必须为一个类做一些Swing的事情,我觉得这听起来很有趣)。
我们的想法是,JTable中任何选定单元格的颜色都会更改为JComboBox中选择的颜色。
以下是在突出显示的单元格(9,7)上点击后的情况:
在其他地方点击后(例如显示在(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;
}
}
我感谢任何提示,我坚持如何解决这个问题。
答案 0 :(得分:3)
请查看Concepts: Editors and Renderers,Writing a Custom Cell Renderer和Using Other Editors,详细了解渲染器和编辑器的实际工作方式。
每次调用getTableCellRendererComponent
时,都需要根据单元格的值和状态完全配置渲染器。所以基本上,你正在做的只是简单地设置一次背景颜色,而不是为任何其他条件更改它,这意味着当任何其他单元格被绘制时(无论出于何种原因),它仍然使用相同的背景颜色。
相反,您应该使用TableModel
中存储的值来决定单元格应该绘制的内容。要做到这一点,你可能需要一个简单的CellEditor
,它可以简单地返回当前选择的颜色
也许像......
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
来显示它。