具有JSpinner的JTable启用/禁用
我有一个3列的JTable.第2列是一个复选框,我想为该行启用/禁用JSpinner.
I've got a 3 column JTable. Column 2 is a checkbox which I want to enable/disable the JSpinner for that row.
除了一件事之外,我已经按照自己的方式工作了-JSpinner实际上看起来并不像它的已禁用(文本和微调按钮为灰色).我不太确定如何实现这一目标.我已经尝试过在JSpinner上强行调用setEnabled(false),但是该表似乎无法正确重绘.
I've got working how I want except for one thing -- The JSpinner doesn't actually look like its disabled (text and spinner buttons greyed out). I'm not quite sure how to attain this. I've tried forcibly calling setEnabled(false) on the JSpinner, but the table doesn't seem to redraw correctly.
以下是我通过其他StackOverflow示例工作的一些代码:
Here is some code I've gotten working through other StackOverflow examples:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class SpinnerTable {
public JComponent makeUI() {
String[] columnNames = { "Name", "Spinner Enable", "Spinner" };
final Object[][] data = { { "aaa", true, 1 }, { "bbb", true, 10 },
{ "ccc", true, 10 } };
final DefaultTableModel model = new DefaultTableModel(data, columnNames) {
@Override
public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
JTable table = new JTable(model) {
@Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
}
@Override
public boolean isCellEditable(int row, int column) {
if (column == 2)
return (Boolean) model.getValueAt(row, 1);
return super.isCellEditable(row, column);
}
};
table.setRowHeight(36);
table.setAutoCreateRowSorter(true);
TableColumn column = table.getColumnModel().getColumn(2);
column.setCellRenderer(new ComboBoxCellRenderer());
column.setCellEditor(new ComboBoxCellEditor());
return new JScrollPane(table);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new SpinnerTable().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class SpinnerPanel extends JPanel {
protected JSpinner spinner = new JSpinner() {
@Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
return new Dimension(40, d.height);
}
};
public SpinnerPanel() {
super();
setOpaque(true);
add(spinner);
}
}
class ComboBoxCellRenderer extends SpinnerPanel implements TableCellRenderer {
public ComboBoxCellRenderer() {
super();
setName("Table.cellRenderer");
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setBackground(isSelected ? table.getSelectionBackground() : table
.getBackground());
if (value != null) {
spinner.setValue(value);
}
return this;
}
}
class ComboBoxCellEditor extends SpinnerPanel implements TableCellEditor {
public ComboBoxCellEditor() {
super();
spinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
fireEditingStopped();
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
fireEditingStopped();
}
});
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
this.setBackground(table.getSelectionBackground());
spinner.setValue(value);
return this;
}
// Copid from DefaultCellEditor.EditorDelegate
@Override
public Object getCellEditorValue() {
return spinner.getValue();
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
MouseEvent e = (MouseEvent) anEvent;
return e.getID() != MouseEvent.MOUSE_DRAGGED;
}
return true;
}
@Override
public boolean stopCellEditing() {
fireEditingStopped();
return true;
};
transient protected ChangeEvent changeEvent = null;
@Override
public boolean isCellEditable(EventObject e) {
return true;
}
@Override
public void cancelCellEditing() {
fireEditingCanceled();
}
@Override
public void addCellEditorListener(CellEditorListener l) {
listenerList.add(CellEditorListener.class, l);
}
@Override
public void removeCellEditorListener(CellEditorListener l) {
listenerList.remove(CellEditorListener.class, l);
}
public CellEditorListener[] getCellEditorListeners() {
return listenerList.getListeners(CellEditorListener.class);
}
protected void fireEditingStopped() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((CellEditorListener) listeners[i + 1])
.editingStopped(changeEvent);
}
}
}
protected void fireEditingCanceled() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((CellEditorListener) listeners[i + 1])
.editingCanceled(changeEvent);
}
}
}
}
当修改第1列时,该表不知道应重新绘制第2列中的单元格.您可以通过手动触发更新来通知表.例如,扩展模型的setValueAt()
:
The table does not know it should repaint the cell in column 2 when column 1 was modified. You can notify the table by firing an update manually. For example, extend model's setValueAt()
:
@Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
if (column == 1)
fireTableRowsUpdated(row, row);
}
这将禁用编辑器,并且微调器将变得不可编辑.如果需要实际从视觉上禁用微调器,则可以在渲染器内部基于isCellEditable
启用/禁用微调器,即:
This will disable the editor and spinner will become not editable. If you need to actually disable the spinner visually, then, inside the renderer you can enable/disable the spinner based on isCellEditable
, ie:
spinner.setEnabled(table.isCellEditable(row, column));
请注意,在当前的实现中,您扩展了JTable
以实现isCellEditable
和setValueAt
.这些实际上应该是模型的一部分.
Note that in your current implementation you extend JTable
to implement isCellEditable
and setValueAt
. These should really be part of the model.