意外的 jtable 自定义渲染器行为
Unexpected jtable custom renderer behavior
我的目标是在 Java Swing 中制作一个基本的像素艺术应用程序(我知道这远非理想,我们必须为 class 使用 Swing 做一些事情,我认为这听起来一种乐趣)。
想法是将 JTable 中任何选定单元格的颜色更改为 JComboBox 中选定的颜色。
这是点击突出显示的单元格 (9,7) 后当前的样子:
并且在点击别处(例如显示的 (0,6) 处)后,它往往会填充两个 space 之间的 space,以及行也是如此。
这当然不理想 - 我只想让一个单元格在每次点击时改变颜色。我是自定义 JTable 渲染的新手,所以我附上了必要的代码,希望有人能帮助我发现我的错误。当我创建 CustomModel class.
的 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;
}
}
我很感激任何提示,我一直在思考如何解决这个问题。
查看 Concepts: Editors and Renderers, Writing a Custom Cell Renderer and Using Other Editors 以了解有关渲染器和编辑器实际工作方式的更多详细信息。
每次调用getTableCellRendererComponent
时,您都需要根据单元格的值和状态完全配置渲染器。所以基本上,您所做的只是简单地设置一次背景颜色,并且永远不会在任何其他情况下更改它,这意味着当任何其他单元格被绘制时(无论出于何种原因),它仍然使用相同的背景颜色。
相反,您应该使用存储在 TableModel
中的值来决定单元格应该绘制什么。为此,您可能需要一个简单的 CellEditor
,它可以简单地 return 当前选择的颜色
也许像...
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;
}
}
}
现在,在任何人扑向我之前。我会用 Color
填充 JComboBox
并使用自定义 ListCellRenderer
来显示它。
我的目标是在 Java Swing 中制作一个基本的像素艺术应用程序(我知道这远非理想,我们必须为 class 使用 Swing 做一些事情,我认为这听起来一种乐趣)。
想法是将 JTable 中任何选定单元格的颜色更改为 JComboBox 中选定的颜色。
这是点击突出显示的单元格 (9,7) 后当前的样子:
并且在点击别处(例如显示的 (0,6) 处)后,它往往会填充两个 space 之间的 space,以及行也是如此。
这当然不理想 - 我只想让一个单元格在每次点击时改变颜色。我是自定义 JTable 渲染的新手,所以我附上了必要的代码,希望有人能帮助我发现我的错误。当我创建 CustomModel class.
的 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;
}
}
我很感激任何提示,我一直在思考如何解决这个问题。
查看 Concepts: Editors and Renderers, Writing a Custom Cell Renderer and Using Other Editors 以了解有关渲染器和编辑器实际工作方式的更多详细信息。
每次调用getTableCellRendererComponent
时,您都需要根据单元格的值和状态完全配置渲染器。所以基本上,您所做的只是简单地设置一次背景颜色,并且永远不会在任何其他情况下更改它,这意味着当任何其他单元格被绘制时(无论出于何种原因),它仍然使用相同的背景颜色。
相反,您应该使用存储在 TableModel
中的值来决定单元格应该绘制什么。为此,您可能需要一个简单的 CellEditor
,它可以简单地 return 当前选择的颜色
也许像...
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;
}
}
}
现在,在任何人扑向我之前。我会用 Color
填充 JComboBox
并使用自定义 ListCellRenderer
来显示它。