我得到一个JTable,其内容是类“item”的Vector。类项包含带有正确getter / setter的数字和字母数字字段,但字段alt是字符串的ArrayList除外。对于本专栏,我打算使用comboBox样式的渲染器和编辑器,以便选择一个可用的选项并显示选择。 alt字段因行而异,这就是我的问题所在。我在这里看到了很多这样的渲染器的例子,但是在所有的例子中,每行的可用选择是相同的。这是代码:
public class item extends Vector {
private int no, code;
private String ....;
private List<String> alt;
@SuppressWarnings("unchecked")
public item(int no, int code, ...., List alt) {
super();
this.add(no);
this.add(code);
....
this.add(alt);
}
public int getNo() {
return (int) this.get(0);
}
public void setNo(int no) {
this.no = no;
}
// other setter/getters...
public void setAlt(List<String> alt) {
this.alt = alt;
}
@SuppressWarnings("unchecked")
public List<String> getAlt() {
return (List<String>) this.get(6);
}
@SuppressWarnings("all")
public Vector getAsVector() {
// ArrayList<Object> a= new ArrayList<Object>();
Vector a = new Vector(7);
a.add(no);
a.add(sifra);
a.add(red1);
a.add(red2);
a.add(sastojci);
a.add(eanKod);
a.add(alt);
return a;
}
}
JTable获得必要的功能:
public Class getColumnClass(int ci){
if (ci==6) return JComboBox.class;
else return String.class;
}
@Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
item it = data.get(rowIndex);
switch (columnIndex) {
case 0:
it.setNo((int) value);
break;
case 1:
it.setCode((int) value);
break;
case 2:
....
case 6:
it.setAlt((List<String>) value);
break;
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object returnValue = null;
item it = data.get(rowIndex);
switch (columnIndex) {
case 0:
returnValue = it.getNo();
break;
case 1:
returnValue = it.getCode();
break;
case 2:
...
case 6:
returnValue = it.getAlt();
break;
}
return returnValue;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex > 0;
}
最后是渲染器/编辑器类:
String[] sval = {"alfa", "Beta", "Gamma"}; //dummy array
protected class ComboRenderer extends JComboBox implements TableCellRenderer {
public ComboRenderer(){
super(sval); //works, but this is not I want
// here should be used a similar super(list of options for a certain row), but how to get it?
// setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
this.setSelectedItem(items);
return this;
}
}
protected class ComboEditor extends AbstractCellEditor
implements TableCellEditor {
private List<String> alt;
protected ComboEditor() {
super();
}
@Override
public Object getCellEditorValue() {
return this.alt;
}
@SuppressWarnings("unchecked")
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value instanceof List) {
this.alt = (List<String>) value;
}
JComboBox<String> combo = new JComboBox<String>();
// combo.setEditable(true); //does not work for editable combobox!
for (String a : alt) {
combo.addItem(a);
}
combo.setSelectedItem(alt);
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
return combo;
}
}
以下是问题:
1)渲染器显然不适用于构造函数的错误部分(super(something))。但是在这部分我无法获得渲染的项目,所以我无法获得初始化的选择列表。如何解决这个问题?
2)编辑器似乎运行良好,但是当我从行中移动时,它再次显示旧值。我应该在这里保存一些以及如何保存?没有新数据,只需在此项目的可用选项之间进行选择。
3)如何从外部达到某一行的选定值,比方说打印?
4)如何才能获得可编辑的Combobox而不是固定?这条线
// combo.setEditable(true); //does not work for editable combobox!
在这种情况下不起作用
答案 0 :(得分:0)
与此同时,我解决了问题(第4号除外),但我认为这必须是一个更好的解决方案,所以我还在等待替代解决方案。
首先,我注意到,因为我有一个且只有渲染器的实例,
的返回值setSelectedItems(<available options>)
无论在那里选择什么,也将返回所有其他行的FIRST行中的选择。所以我决定为每一行创建一个渲染器实例。这意味着JTable构造函数将包含以下代码:
rendererList = new ArrayList<ComboRenderer>();
....
// create the Array of renderers, one for each row
for (int cnt=0; cnt<data.size(); cnt++){
ComboRenderer a = new ComboRenderer();
a.setOptions(cnt);
rendererList.add(a);
}
....
// telling to JTable which renderer to use for every cell
@Override
public TableCellRenderer getCellRenderer(int row, int coll) {
if (coll==6) return rendererList.get(row);
else return this.getDefaultRenderer(this.getColumnClass(coll));
}
渲染器和编辑器类现在看起来如下:
protected class ComboRenderer extends JComboBox implements TableCellRenderer {
List<String> items;
int selected;
//selected will contains the index of selected option, changed through the cell editor as listener
public ComboRenderer(){
super();
setOpaque(true);
selected=0; //initial value
}
public void setSel(int k) {
selected=k;
}
public int getSel() {
return selected;
}
// filling each renderer with available options;
@SuppressWarnings("unchecked")
public void setOptions(int row) {
items = data.get(row).getAlt();
for (String a : items) {
this.addItem(a);
}
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
this.setSelectedIndex(selected);
return this;
}
}
class ComboEditor extends AbstractCellEditor implements TableCellEditor{
private List<String> alt ;
protected ComboEditor() {
super();
}
@Override
public Object getCellEditorValue() {
return this.alt;
}
@SuppressWarnings("unchecked")
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value instanceof List) {
this.alt = (List<String>) value;
}
JComboBox<String> combo = new JComboBox<String>();
for (String a : alt) {
combo.addItem(a);
}
final ComboRenderer rend= rendererList.get(row);
// adding actionlistener to letting know the renderer the selection
combo.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent arg0) {
int i=((JComboBox<?>) arg0.getSource()).getSelectedIndex();
// telling the renderer the selection
rend.setSel(i);
}
});
combo.setSelectedIndex(rend.getSel());
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
return combo;
}
}
它现在正在运行,但代码对我来说非常笨拙。必须有办法以更优雅的方式解决这个问题。我简直无法相信每一行必须有一个独特的渲染器,这是浪费内存。有什么想法吗?