2010-08-31 14 views
5

Voglio essere in grado di avere un JPanel in una cella con un JButton che funziona un po 'quando si fa clic.JTable: pulsanti nel pannello personalizzato nella cella

ho cercato HOWTO circa Editori cella, ma tutti gli esempi parlano di sostituire la cella con un altro componente (ad esempio, sostituire un int con un JTextField ecc) La mia situazione è un po 'diverso:

Ho il seguente ADT

class MyClass { 
    public String title; 
    public String url; 
    public String path; 
    public int annotations; 
} 

ho creato un modello di cella di una tabella personalizzata che ha 1 colonna e la classe per quella colonna è MyClass. Poi ho creato un renderer di celle per quella classe che restituisce un JPanel come illustrato di seguito:

MyClass Cell Renderer

Come si può vedere, il JPanel contiene un pulsante. Voglio questo pulsante per avviare una JFrame ogni volta che si fa clic. Qualche idea?

Se si suggerisce Cell Editor, si prega di essere un po 'più specifici su come farlo. Se possibile, fornire qualche pseudo-codice.

Grazie.

P.S. Sono abbastanza sicuro che il titolo di questa domanda abbia bisogno di un po 'di lavoro. ;)

risposta

7

Dopo il coding.mof's reply, ho finalmente fatto quello che volevo. Tuttavia, volevo una risposta più completa a questa domanda, quindi ne fornirò una io stesso.

Quindi, i Renderizzatori di celle disegnano semplicemente il componente e non consentono alcuna interazione al suo interno. Mentre gli editor di celle lo fanno.

Inizialmente, tutte le celle di JTable sono componenti restituiti dal programma di rendering registrato. Tuttavia, quando viene selezionata una cella, questo componente viene sostituito da un componente che viene restituito dall'editor. Questi due possono effettivamente essere diversi componenti! Che sono abbastanza sicuro di poter sfruttare questo vantaggio e creare alcune celle funky: P

Ad ogni modo, in questo esempio, sia il renderer che l'editor visualizzano lo stesso componente, quindi creeremo un componente che verrà utilizzato da entrambi.

In primo luogo, abbiamo bisogno di creare un TableModel che restituisce la nostra ADT:

class MyClassTableModel extends DefaultTableModel { 
    List<MyClass> data; 

    public MyClassTableModel(List<MyClass> data) { 
    this.data = data; 
    } 

    public Class<?> getColumnClass(int columnIndex) { return MyClass.class; } 
    public int getColumnCount() { return 1; } 
    public String getColumnName(int columnIndex) { return "MyClass"; } 
    public int getRowCount() { return (data == null) ? 0 : data.size(); } 
    public Object getValueAt(int rowIndex, int columnIndex) { return data.get(rowIndex); } 
    public boolean isCellEditable(int rowIndex, int columnIndex) { return true; } 
} 

Ora, creiamo un componente che verrà condiviso tra il rendering e l'Editor:

class MyClassCellComponent extends JPanel() { 
    MyClass myClass; 

    public MyClassCellComponent() { 
    // initialize components (labels, buttons, etc.) 
    // add action listeners 
    } 

    public void updateData(MyClass myClass, boolean isSelected, JTable table) { 
    this.myClass = myClass; 
    // update buttons, labels etc. accordingly 
    } 
} 

L'isSelected e i parametri della tabella sono usati per rendere lo sfondo del pannello e sono opzionali.Ecco come il renderer utilizza il nostro componente:

class MyClassCellRenderer implements TableCellRenderer { 
    MyClassCellComponent panel; 

    public MyClassCellRenderer() { 
    panel = new MyClassCellComponent(); 
    } 

    public Component getTableCellRendererComponent(JTable table, Object value,  boolean isSelected, boolean hasFocus, int row, int column) { 
    MyClass myClass = (MyClass)value; 
    panel.updateData(myClass, isSelected, table); 
    return panel; 
    } 
} 

Ed ecco come l'editor usa:

class MyClassCellEditor extends AbstractCellEditor { 
    MyClassCellComponent panel; 
    public MyClassCellEditor() { 
    panel = new MyClassCellComponent(); 
    } 
    public Component getTableCellEditorComponent(JTable table, Object value,  boolean isSelected, int row, int column) { 
    MyClass myClass = (MyClass)value; 
    panel.updateData(myClass, true, table); 
    return panel; 
    } 
    public Object getCellEditorValue() { 
    return null; 
    } 
} 

Questo è tutto. Ora possiamo semplicemente creare una JTable come segue:

JTable myClassTable = new JTable(new MyClassTableModel()); 
myClassTable.setDefaultRenderer(MyClass.class, new MyClassCellRenderer()); 
myClassTable.setDefaultEditor(MyClass.class, new MyClassCellEditor()); 

E abbiamo finito!

P.S. Sono abbastanza sicuro che possiamo combinare Renderer e Editor in una singola classe, estendere AbstractCellEditor e implementare TableCellRenderer, ma non sono sicuro delle prestazioni.

5
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor { 

JComponent pan = new JPanel(); 

public MyTableCellEditor() { 
    pan.add(btn); 
    // add all elments you need to your panel 
    btn.addActionListener(/* the listener which will handle the events */); 
} 

public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex) { 
    btn.setText(/* according to row or whatever*/); 
    // set all elemnts of you panel to the according values 
    // or add dynamically an action listener 
    return pan; 
} 
public Object getCellEditorValue() { return new Void(); } 
} 

Quindi nel listener dovrai controllare la selezione della tabella in modo da poter rispondere in modi diversi per ogni riga. Se si desidera mantenere tutti gli elementi in una colonna, è possibile sostituire JButton con il pannello contenente tutti i componenti. JTable inoltrerà quindi tutti gli eventi a quel JPanel.

+0

Ciò significa che non ho più bisogno del mio CellRenderer? Lo faccio in un CellEditor? – pek

+0

No. Se si esegue questa operazione, verrà visualizzata una cella vuota. JTable utilizza internamente il renderer solo per la visualizzazione dei dati. Ma se si fa clic su una cella diventerà modificabile e verrà visualizzato il componente fornito dal celleditor. –

+0

Sì, l'ho provato subito dopo che ti ho chiesto e in effetti questo è il caso. Grazie! – pek

0

È possibile creare una tabella con più colonne, quindi è possibile aggiungere una colonna separata per contenere il pulsante. La classe Table Button Column ti consente di farlo facilmente.

+1

Volevo evitare questo perché voglio essere in grado di posizionare i miei componenti come voglio (come si vede dallo screenshot) e non uno vicino all'altro. – pek

+0

Quindi potrebbe essere ancora più semplice avere due colonne. Uno per i tuoi dati e uno per il pulsante. Puoi rimuovere le linee verticali dalla tabella in modo che assomigli ancora a una singola colonna. – camickr

Problemi correlati