我正在尝试在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;
}
}
答案 0 :(得分:2)
你显然误解了编辑器和渲染器的角色。编辑器允许用户编辑单元格的状态,渲染器渲染单元格的状态。
他们通过使用TableModel
来做到这一点。首先查看Concepts: Editors and Renderers和Using 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];
}
});
“颜色”单元格的单元格值应为true
或false
(它们可以是您想要的任何其他“开启”/“关闭”值,只要编辑器和渲染器知道如何处理它们,但是对于这个例子,我正在使用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
,但这有两个问题。 DefaultCellEditor
从JCheckBox
派生单元格值,而不是其他某些状态(因此它总是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
状态
因为没有人相信我,一个可运行的例子
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;
}
}
可以使用鼠标或键盘切换按钮。