我有一个3列JTable。第2列是一个复选框,我想为该行启用/禁用JSpinner。
我已经开始工作了我想要的东西,除了一件事 - JSpinner实际上看起来不像它的禁用(文本和微调按钮灰显)。我不太清楚如何实现这一目标。我试过在JSpinner上强行调用setEnabled(false),但表似乎没有正确重绘。
以下是我通过其他StackOverflow示例编写的一些代码:
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);
}
}
}
}
答案 0 :(得分:4)
该表不知道在修改第1列时应重新绘制第2列中的单元格。您可以通过手动触发更新来通知表。例如,扩展模型的setValueAt()
:
@Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
if (column == 1)
fireTableRowsUpdated(row, row);
}
这将禁用编辑器,并且微调器将变得不可编辑。如果您需要在视觉上实际禁用微调器,那么在渲染器内,您可以基于isCellEditable
启用/禁用微调器,即:
spinner.setEnabled(table.isCellEditable(row, column));
请注意,在您当前的实施中,您将JTable
扩展为实施isCellEditable
和setValueAt
。这些应该是模型的一部分。