我有一个带有2列的JTable组件,对于第二列我只想为一个单元添加一个JComboBox,遵循oracle文档我创建了自己的单元格编辑器,并添加了JComboBox但是之后所有的来自该列的其他细胞变得无法编辑。 这是一个例子:
添加JComboBox后,我无法编辑其他单元格
我的代码:
DefaultTableModel model = new DefaultTableModel(textosTabela, stubColumnNames);
tabela.setModel(model);
tabela.setBorder(new LineBorder(Color.black));
tabela.setGridColor(Color.black);
tabela.setShowGrid(true);
tabela.setPreferredSize(new Dimension(290, 132));
tabela.setRowHeight(22);
tabela.getColumnModel().getColumn(0).setPreferredWidth(160);
tabela.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
TableColumn tm = tabela.getColumnModel().getColumn(0);
tm.setCellRenderer(new ColorColumnRenderer(Color.lightGray));
TableColumn comboCol1 = tabela.getColumnModel().getColumn(1);
JComboBox comboBox = new JComboBox(valoresComboBox);
comboBox.setSelectedIndex(0);
comboCol1.setCellEditor(new ComboBoxEditor(1,3,comboBox));
CellEditor代码:
public class ComboBoxEditor extends DefaultCellEditor {
private String[] values;
private String selectedValue;
private int column = -1;
private int row = -1;
public ComboBoxEditor(JComboBox values) {
super(values);
// TODO Auto-generated constructor stub
}
public ComboBoxEditor(int column, int row, JComboBox values) {
super(values);
this.column = column;
this.row = row;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
// TODO Auto-generated method stub
Component c = table.getEditorComponent();
if(column == this.column && row == this.row) {
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
return null;
}
}
答案 0 :(得分:2)
这是一个逐行返回不同组合框的示例。如果该行没有组合框,则使用默认编辑器:
private String processAction(String actionJson) {
String[] data = actionJson.split(":");
int limit = data[1].length() - 3;
String result = data[1].substring(1, limit);
return result;
}
密钥是覆盖import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableComboBoxByRow extends JPanel
{
List<String[]> editorData = new ArrayList<String[]>(3);
public TableComboBoxByRow()
{
setLayout( new BorderLayout() );
// Create the editorData to be used for each row
editorData.add( new String[]{ "Red", "Blue", "Green" } );
editorData.add( new String[]{ "Circle", "Square", "Triangle" } );
editorData.add( new String[]{ "Apple", "Orange", "Banana" } );
// Create the table with default data
Object[][] data =
{
{"Color", "Red"},
{"Shape", "Square"},
{"Fruit", "Banana"},
{"Plain", "Text"}
};
String[] columnNames = {"Type","Value"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable(model)
{
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 1 && row < 3)
{
JComboBox<String> comboBox1 = new JComboBox<String>( editorData.get(row));
return new DefaultCellEditor( comboBox1 );
}
else
return super.getCellEditor(row, column);
}
};
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
// table.getColumnModel().getColumn(1).setCellRenderer(new ComboBoxRenderer2() );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Table Combo Box by Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TableComboBoxByRow() );
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
方法,而不是创建自定义渲染器。
答案 1 :(得分:2)
TableModel
应该指定哪些单元格可以编辑,默认情况下,DefaultTableModel
会使所有单元格都可编辑。
在TableCellEditor
,你有......
if (column == this.column && row == this.row) {
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
这似乎是为编辑做出决定,例如模型应该是
DefaultTableModel model = new DefaultTableModel(textosTabela, stubColumnNames) {
@Override
public boolean isCellEditable(int row, int column) {
return row == 3 && column == 1;
}
};
只需使用DefaltCellEditor
打包JComboBox
JComboBox comboBox = new JComboBox(valoresComboBox);
DefaultCellEditor editor = new DefaultCellEditor(comboBox);
TableColumn comboCol1 = tabela.getColumnModel().getColumn(1);
我可能会指出,一般来说,JTable
作为属性表编辑器并不是很好,其中每行的单元格值不同
可重用性和可配置性是我对任何类型的实现的两个主要关注点。现在,桌子有责任决定如何渲染或编辑事物,这就是渲染器和编辑器的原因。我们需要的是一些在API中提供可配置元素的方法,它可以做出我们需要的决策,并让表格完成它目前正在做的工作。
由于JTable
并非真正设计用于处理特定列的多种类型的数据,以及不同的渲染器和编辑器,因此我们需要提供该功能。
让我们从关键元素属性开始。属性有三个基本元素,名称,值和类型。
public interface Property<T> {
public String getName();
public T getValue();
public Class<T> getType();
public void setValue(T value);
}
我确实考虑为可变属性制作另一个interface
,但如果需要,您可以轻松地向此界面添加readOnly
属性。
因为我懒惰......
public class DefaultProperty<T> implements Property<T> {
private final String name;
private T value;
private final Class<T> type;
public DefaultProperty(String name, T value, Class<T> type) {
this.name = name;
this.value = value;
this.type = type;
}
@Override
public String getName() {
return name;
}
@Override
public T getValue() {
return value;
}
@Override
public Class<T> getType() {
return type;
}
@Override
public void setValue(T value) {
this.value = value;
}
}
现在,我们需要的模型可以管理我们的Property
以及与JTable
的合同...
public interface PropertySheetModel extends TableModel {
public Property getPropertyAt(int row);
}
因为我懒惰......
public class DefaultPropertySheeModel extends AbstractTableModel implements PropertySheetModel {
private List<Property> properties;
public DefaultPropertySheeModel(List<Property> properties) {
this.properties = new ArrayList<>(properties);
}
@Override
public int getRowCount() {
return getProperties().size();
}
@Override
public int getColumnCount() {
return 2; // Key/value
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Property p = getPropertyAt(rowIndex);
Object value = null;
switch (columnIndex) {
case 0:
value = p.getName();
break;
case 1:
value = p.getValue();
break;
}
return value;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
Property p = getPropertyAt(rowIndex);
p.setValue(aValue);
fireTableCellUpdated(rowIndex, columnIndex);
}
@Override
public Property getPropertyAt(int row) {
return getProperties().get(row);
}
protected List<Property> getProperties() {
return properties;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex != 0;
}
}
创建动态模型并不会花费太多时间,您可以添加/删除Property
,这超出了此答案的范围;)
好的,现在我们需要开始为我们制定更复杂的决策。这是代表进来的地方,我们可以用它来回答我们不想回答的一些问题
public interface PropertySheetDelegate {
public TableCellEditor getCellEditorFor(Property property);
public void setCellEditorFor(Property property, TableCellEditor editor);
public void setCellEditorFor(Class type, TableCellEditor editor);
public TableCellRenderer getCellRendererFor(Property property);
public void setCellRendererFor(Property property, TableCellRenderer editor);
public void setCellRendererFor(Class type, TableCellRenderer editor);
}
因为我懒惰......
public class DefaultPropertySheetDelegate implements PropertySheetDelegate {
private Map<Property, TableCellEditor> propertyEditors;
private Map<Class, TableCellEditor> typeEditors;
private Map<Property, TableCellRenderer> propertyRenderers;
private Map<Class, TableCellRenderer> typeRenderers;
public DefaultPropertySheetDelegate() {
propertyEditors = new HashMap<>(25);
typeEditors = new HashMap<>(25);
propertyRenderers = new HashMap<>(25);
typeRenderers = new HashMap<>(25);
JTextField field = new JTextField();
field.setBorder(null);
DefaultCellEditor editor = new DefaultCellEditor(field);
editor.setClickCountToStart(1);
setCellEditorFor(String.class, editor);
}
@Override
public TableCellEditor getCellEditorFor(Property property) {
TableCellEditor editor = propertyEditors.get(property);
if (editor == null) {
editor = typeEditors.get(property.getType());
}
return editor;
}
@Override
public void setCellEditorFor(Property property, TableCellEditor editor) {
propertyEditors.put(property, editor);
}
@Override
public void setCellEditorFor(Class type, TableCellEditor editor) {
typeEditors.put(type, editor);
}
@Override
public void setCellRendererFor(Class type, TableCellRenderer renderer) {
typeRenderers.put(type, renderer);
}
@Override
public void setCellRendererFor(Property property, TableCellRenderer renderer) {
propertyRenderers.put(property, renderer);
}
@Override
public TableCellRenderer getCellRendererFor(Property property) {
TableCellRenderer renderer = propertyRenderers.get(property);
if (renderer == null) {
renderer = typeRenderers.get(property.getType());
}
return renderer;
}
}
现在,这个实现只是处理TableCellEditor
,实际上,你应该也可以处理渲染器。
最后,我们需要一些方法来展示它,这是一个自定义的JTable
(显然),它使用PropertySheetDelegate
和PropertySheetModel
来呈现管理的数据...
public class PropertySheet extends JTable {
private PropertySheetDelegate propertySheetDelegate;
public PropertySheet(PropertySheetDelegate controller, PropertySheetModel model) {
super(model);
setDelegate(controller);
}
public PropertySheet() {
super();
}
@Override
public void setModel(TableModel dataModel) {
if (dataModel instanceof PropertySheetModel || dataModel == null) {
super.setModel(dataModel);
} else {
throw new UnsupportedOperationException("Unsupported PropertySheetModel " + dataModel.getClass().getName());
}
}
public PropertySheetDelegate getPropertySheetDelegate() {
return propertySheetDelegate;
}
public void setDelegate(PropertySheetDelegate value) {
if (propertySheetDelegate != value) {
PropertySheetDelegate old = propertySheetDelegate;
this.propertySheetDelegate = value;
firePropertyChange("propertySheetController", old, value);
}
}
@Override
public TableCellEditor getCellEditor(int row, int column) {
TableCellEditor editor = null;
// Assumes that only the values can be modified
if (column == 1) {
PropertySheetDelegate delegate = getPropertySheetDelegate();
if (delegate != null) {
PropertySheetModel model = (PropertySheetModel) getModel();
Property property = model.getPropertyAt(row);
editor = delegate.getCellEditorFor(property);
System.out.println("Editor for " + property + " = " + editor);
if (editor == null) {
editor = getDefaultEditor(property.getType());
System.out.println("Default Editor for " + property.getType() + " = " + editor);
}
} else {
editor = super.getCellEditor(row, column);
}
}
return editor;
}
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
TableCellRenderer renderer = null;
if (column == 1) {
PropertySheetDelegate delegate = getPropertySheetDelegate();
if (delegate != null) {
PropertySheetModel model = (PropertySheetModel) getModel();
Property property = model.getPropertyAt(row);
renderer = delegate.getCellRendererFor(property);
if (renderer == null) {
renderer = getDefaultRenderer(property.getType());
}
} else {
renderer = super.getCellRenderer(row, column);
}
} else {
renderer = super.getCellRenderer(row, column);
}
return renderer;
}
}
最后,还有一些让它有用的东西......
List<Property> properties = new ArrayList<>(25);
properties.add(new DefaultProperty<>("Name", null, String.class));
properties.add(new DefaultProperty<>("Description", null, String.class));
properties.add(new DefaultProperty<>("Quanity", null, Integer.class));
properties.add(new DefaultProperty<>("Warrenty", null, Integer.class));
properties.add(new DefaultProperty<>("Returns", null, Boolean.class));
// This is our custom editor
DefaultCellEditor editor = new DefaultCellEditor(new JComboBox(new Integer[]{1, 2, 3, 4, 5}));
PropertySheetDelegate controller = new DefaultPropertySheetDelegate();
controller.setCellEditorFor(properties.get(2), editor);
PropertySheetModel model = new DefaultPropertySheeModel(properties);
PropertySheet propertySheet = new PropertySheet(controller, model);
setLayout(new BorderLayout());
add(new JScrollPane(propertySheet));
答案 2 :(得分:0)
使用新的更新可以更轻松地使用默认的渲染器和编辑器。
但是,在JTable
中,GenericEditor
使用getColumnClass()
方法将输入到文本字段的字符串转换为正确的类,以便将值保存到TableModel。 / p>
您的TableModel正在使用默认的getColumnClass()实现,因此所有值都被视为对象,并且只是存储为字符串。
您可以在编辑Integer或Double值之前和之后单击“所选行类”来验证这一点。 (ComboBoxEditor和BooleanEditor没有问题,因为它们实现了自己的getCellEditorValue()方法以返回正确的值。)
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
public class PropertyTest extends JPanel
{
public PropertyTest()
{
List<Property> properties = new ArrayList<>(25);
properties.add(new DefaultProperty<>("String", "String", String.class));
properties.add(new DefaultProperty<>("Integer Combo", new Integer(2), Integer.class));
properties.add(new DefaultProperty<>("Boolean", Boolean.TRUE, Boolean.class));
properties.add(new DefaultProperty<>("Integer", new Integer(1), Integer.class));
properties.add(new DefaultProperty<>("Double", new Double(1.25), Double.class));
// This is our custom editor
DefaultCellEditor editor = new DefaultCellEditor(new JComboBox(new Integer[]{1, 2, 3, 4, 5}));
PropertySheetDelegate delegate = new DefaultPropertySheetDelegate();
delegate.setCellEditorFor(properties.get(1), editor);
PropertySheetModel model = new DefaultPropertySheetModel(properties);
final PropertySheet propertySheet = new PropertySheet(delegate, model);
setLayout(new BorderLayout());
add(new JScrollPane(propertySheet));
JButton button = new JButton("Class of Selected Row");
add(button, BorderLayout.SOUTH);
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
int row = propertySheet.getSelectedRow();
System.out.println(propertySheet.getValueAt(row, 1).getClass() );
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("PropertyTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PropertyTest());
frame.setLocationByPlatform( true );
frame.setSize(400, 400);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
我认为您需要覆盖getColumnClass()
的{{1}}方法,因为它可以访问正在编辑的行,而JTable
则没有。
以下是我添加到PropertySheet类的代码:
TableModel
虽然我相信你会找到更好的方法来实现它:)