2016-11-06 17 views
0

Я получаю JTable, содержимое которого является вектором класса «item». Элемент класса содержит числовые и буквенно-цифровые поля с правильными геттерами/сеттерами, за исключением поля alt, которое является ArrayList строк. Для этого столбца я намеревался использовать рендеринг и редактор в стиле comboBox, чтобы выбрать один из доступных вариантов и показать выбор. Поле alt отличается от строки к строке, и это то, что делает меня проблемой. Я видел здесь множество примеров для такого средства визуализации, но во всех примерах доступные варианты были одинаковыми для каждой строки. Вот код:Настройка редактора/редактора типа Combobox в JTable

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) Средство визуализации не работает явно для неправильной части конструктора (супер (что-то)). Но в этой части я не могу получить отображаемый элемент, поэтому я не могу получить список вариантов для инициализации. Как решить эту проблему?

2) Редактор, похоже, работает хорошо, но когда я перешел из строки, он снова показывает старое значение. Должен ли я здесь спать и как? Нет новых данных, просто выберите между вариантами, доступными для этого элемента.

3) Как достичь выбранного значения для определенного ряда извне, допустим, для печати?

4) Как можно будет получить редактируемый Combobox вместо фиксированного? Линия

// combo.setEditable(true); //does not work for editable combobox! 

не будет работать в этом случае

ответ

0

В то же время я решаемой проблемы (за исключением нет. 4), но я думаю, что должен быть лучшим решением, поэтому я все еще жду альтернативные решения ,

Для первого, я заметил, что, так как я получил один и только экземпляр визуализатора, возвращаемое значение

setSelectedItems(<available options>) 

вернет выбор в первом ряду для всех остальных строк тоже, независимо от того, что был выбран там , Поэтому я решил сделать один экземпляр рендерера для каждой строки. Это означает, что 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; 
    } 
} 

Он работает сейчас, но код выглядит для меня очень неуклюж , Должен быть способ решить эту проблему на более элегантном пути. Я просто не могу поверить, что для каждой строки я должен иметь отдельный рендерер, это пустая трата памяти. Есть ли у кого-нибудь идеи?