JComboBox in JTable con valori diversi a seconda della riga selezionata

di il
9 risposte

JComboBox in JTable con valori diversi a seconda della riga selezionata

Salve, sto cercando di inserire nel mio programma una JTable che ha una colonna contenente una JComboBox, tutto funzionante ma quando seleziono un elemento dalla JComboBox la selezione non rimane nella cella. Innanzitutto ho implementato il modello della tabella in questo modo:

public class ModelloTabellaMatch extends AbstractTableModel {

    private List<Match> listaMatch = new ArrayList<Match>();

    public ModelloTabellaMatch(List<Match> listaMatch) {
        this.listaMatch = listaMatch;
    }
    
    @Override
    public int getRowCount() {
        return listaMatch.size();
    }

    @Override
    public int getColumnCount() {
        return 6;
    }

    @Override
    public String getColumnName(int column) {
        if (column == 0) {
            return "Data piazzamento";
        } else if (column == 1) {
            return "Nome match";
        } else if (column == 2) {
            return "Profitto/Perdita";
        } else if (column == 3) {
            return "Inizio evento";
        } else if (column == 4) {
            return "Esito";
        } else if (column == 5) {
            return "Descrizione";
        }
        return "";
    }
    
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Match match = listaMatch.get(rowIndex);
        if (columnIndex == 0) {
            return match.getDataPiazzamentoScommesse();
        } else if (columnIndex == 1) {
            return match.getNome();
        } else if (columnIndex == 2) {
            return match.getProfittoPerdita();
        } else if (columnIndex == 3) {
            return match.getDataInizioEvento();
        } else if (columnIndex == 4) {
            return new JComboBox<Conto>();
        } else if (columnIndex == 5) {
            return match.getDescrizione();
        }
        return null;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }

    public List<Match> getListaMatch() {
        return listaMatch;
    }

    public void setListaMatch(List<Match> listaMatch) {
        this.listaMatch = listaMatch;
    }
    
}
Poi il Renderer per gestire le JComboBox nella colonna; tabellaMatch.getColumn("Esito").setCellRenderer(new RendererComboConti());
in questo modo:

public class RendererComboConti implements TableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        if (!(value instanceof JComboBox)) return null;
        JComboBox<Conto> comboConti = (JComboBox<Conto>) value;
        ModelloTabellaMatch modello = (ModelloTabellaMatch) table.getModel();
        Match match = modello.getListaMatch().get(row);
        for (Conto conto : match.getListaConti()) {
            comboConti.addItem(conto);
        }
        return comboConti;
    }
    
}
E per quanto riguarda il CellEditor ho provato varie implementazioni ma nessuna funziona quindi attualmente non ho ancora implementato il CellEditor... Sapreste darmi una mano? Ci sto perdendo fin troppo tempo davvero

9 Risposte

  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    Devuanx86_64 ha scritto:


    quando seleziono un elemento dalla JComboBox la selezione non rimane nella cella.
    Approccio sbagliato. Il getValueAt del model innanzitutto deve solo esporre DATI .... non componenti (come JComboBox). E chiaramente ci deve poi essere la implementazione del setValueAt che riceve i dati, tra cui come minimo il dato scelto dal editor-combobox per quella colonna.

    Il fatto che per una colonna (es. la tua di indice 4) ci sia un JComboBox, lo si gestisce seguendo quanto è scritto nel tutorial ufficiale: Using a Combo Box as an Editor

    Ovvero: si imposta esplicitamente un DefaultCellEditor con il JComboBox sulla colonna interessata. Nello scenario normale la cella appare come un combobox SOLO quando si entra in fase di edit. Altrimenti la cella resta come normale label uguale ad altre celle. Se si vuole far "vedere" il combobox anche normalmente, c'è da implementare un apposito cell renderer. Ma questo è un "di più", non è obbligatorio e dipende dai gusti ...
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    andbin ha scritto:


    Devuanx86_64 ha scritto:


    quando seleziono un elemento dalla JComboBox la selezione non rimane nella cella.
    Approccio sbagliato. Il getValueAt del model innanzitutto deve solo esporre DATI .... non componenti (come JComboBox). E chiaramente ci deve poi essere la implementazione del setValueAt che riceve i dati, tra cui come minimo il dato scelto dal editor-combobox per quella colonna.

    Il fatto che per una colonna (es. la tua di indice 4) ci sia un JComboBox, lo si gestisce seguendo quanto è scritto nel tutorial ufficiale: Using a Combo Box as an Editor

    Ovvero: si imposta esplicitamente un DefaultCellEditor con il JComboBox sulla colonna interessata. Nello scenario normale la cella appare come un combobox SOLO quando si entra in fase di edit. Altrimenti la cella resta come normale label uguale ad altre celle. Se si vuole far "vedere" il combobox anche normalmente, c'è da implementare un apposito cell renderer. Ma questo è un "di più", non è obbligatorio e dipende dai gusti ...
    Intanto grazie mille per aver risposto
    Comunque quale valore dovrei ritornare di preciso alla cella 4 nel modello della tabella? un Conto?
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    Devuanx86_64 ha scritto:


    Comunque quale valore dovrei ritornare di preciso alla cella 4 nel modello della tabella? un Conto?
    Tecnicamente puoi anche restituire un oggetto di tua classe Conto. La questione è che il renderer predefinito (ma anche il JComboBox usato come "editor") mostra semplicemente e banalmente il risultato del toString() invocato sull'oggetto.

    Quindi il tuo Conto ha un toString() che fornisce una rappresentazione in stringa appropriata per essere mostrata su cella/combobox? Se sì, ok. Se no, c'è da fare un'altra scelta.
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    andbin ha scritto:


    Devuanx86_64 ha scritto:


    Comunque quale valore dovrei ritornare di preciso alla cella 4 nel modello della tabella? un Conto?
    Tecnicamente puoi anche restituire un oggetto di tua classe Conto. La questione è che il renderer predefinito (ma anche il JComboBox usato come "editor") mostra semplicemente e banalmente il risultato del toString() invocato sull'oggetto.

    Quindi il tuo Conto ha un toString() che fornisce una rappresentazione in stringa appropriata per essere mostrata su cella/combobox? Se sì, ok. Se no, c'è da fare un'altra scelta.
    In questo codice:
    
    @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Match match = listaMatch.get(rowIndex);
            if (columnIndex == 0) {
                return match.getDataPiazzamentoScommesse();
            } else if (columnIndex == 1) {
                return match.getNome();
            } else if (columnIndex == 2) {
                return match.getProfittoPerdita();
            } else if (columnIndex == 3) {
                return match.getDataInizioEvento();
            } else if (columnIndex == 4) {
                return ?; //In questa cella non posso ritornare un Conto perchè qui dovrebbe esserci la comboBox con la lista dei conti
            }else if (columnIndex == 5) {
                return match.getDescrizione();
            }
            return null;
        }
    
    Non posso ritornare un valore singolo alla colonna 4 perchè il valore lo sceglie l'utente tramite comboBox, a quanto ho capito la selezione rimane nella cella se implemento il setValueAt() ma non saprei davvero come fare, mi potresti fare un piccolo esempio di implementazione se non ti crea troppo disturbo? Mi sarebbe davvero d'aiuto
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    Devuanx86_64 ha scritto:


    Non posso ritornare un valore singolo alla colonna 4 perchè il valore lo sceglie l'utente tramite comboBox
    A questo punto dovresti spiegare cosa è e cosa contiene il tuo Conto.
    E volendo appunto mettere nelle celle di quella colonna un combobox, l'utente sceglierebbe cosa? Cioè che conti ci metteresti e presi da dove?
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    andbin ha scritto:


    Devuanx86_64 ha scritto:


    Non posso ritornare un valore singolo alla colonna 4 perchè il valore lo sceglie l'utente tramite comboBox
    A questo punto dovresti spiegare cosa è e cosa contiene il tuo Conto.
    E volendo appunto mettere nelle celle di quella colonna un combobox, l'utente sceglierebbe cosa? Cioè che conti ci metteresti e presi da dove?
    La tabella contiene dei Match (che contengono una lista di scommesse che a loro volta contengono dei riferimenti ai Conti del giocatore)... alla cella 4 l'utente può selezionare l'esito del match (Cioè su quale Conto ha vinto la scommessa) quindi la comboBox ti permette di scegliere uno tra i conti su cui hai effettuato la scommessa, un Conto è semplicemente una classe contenente un utente e un sito di scommesse e il toString() ritorna solo il nome del sito di scommesse... Non so se è chiaro, spero di si
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    andbin ha scritto:


    Devuanx86_64 ha scritto:


    Non posso ritornare un valore singolo alla colonna 4 perchè il valore lo sceglie l'utente tramite comboBox
    A questo punto dovresti spiegare cosa è e cosa contiene il tuo Conto.
    E volendo appunto mettere nelle celle di quella colonna un combobox, l'utente sceglierebbe cosa? Cioè che conti ci metteresti e presi da dove?
    Ho sistemato il modello della tabella in questo modo (In grassetto le modifiche):
    
    public class ModelloTabellaMatch extends AbstractTableModel {
    
    private List<Match> listaMatch = new ArrayList<Match>();
    
    public ModelloTabellaMatch(List<Match> listaMatch) {
        this.listaMatch = listaMatch;
    }
    
    @Override
    public int getRowCount() {
        return listaMatch.size();
    }
    
    @Override
    public int getColumnCount() {
        return 6;
    }
    
    @Override
    public String getColumnName(int column) {
        if (column == 0) {
            return "Data piazzamento";
        } else if (column == 1) {
            return "Nome match";
        } else if (column == 2) {
            return "Profitto/Perdita";
        } else if (column == 3) {
            return "Inizio evento";
        } else if (column == 4) {
            return "Esito";
        } else if (column == 5) {
            return "Descrizione";
        }
        return "";
    }
    
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Match match = listaMatch.get(rowIndex);
        if (columnIndex == 0) {
            return match.getDataPiazzamentoScommesse();
        } else if (columnIndex == 1) {
            return match.getNome();
        } else if (columnIndex == 2) {
            return match.getProfittoPerdita();
        } else if (columnIndex == 3) {
            return match.getDataInizioEvento();
        } else if (columnIndex == 4) {
            [b]return match.getContoVincente();[/b]
        }else if (columnIndex == 5) {
            return match.getDescrizione();
        }
        return null;
    }
    [b]
    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (!(aValue instanceof Conto)) return;
        Conto conto = (Conto) aValue;
        listaMatch.get(rowIndex).setEsito(conto);
        aggiornaTabella();
    }
    [/b]
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }
    
    public void aggiornaTabella() {
        this.fireTableStructureChanged();
    }
    
    public List<Match> getListaMatch() {
        return listaMatch;
    }
    
    public void setListaMatch(List<Match> listaMatch) {
        this.listaMatch = listaMatch;
    }
    
    E ho aggiunto il CellEditor in questo modo:
    
    public class CellEditorComboConti extends DefaultCellEditor {
    
    private DefaultComboBoxModel model;
    private static final Logger logger = LoggerFactory.getLogger(CellEditorComboConti.class);
    
    public CellEditorComboConti() {
        super(new JComboBox<Conto>());
        this.model = this.model = (DefaultComboBoxModel)((JComboBox)getComponent()).getModel();
    }
    
    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
       if (!(value instanceof JComboBox)) return null;
       model.removeAllElements();
       for (int i = 0; i < 5; i++) {
           model.addElement(i + "");
       }
       return super.getTableCellEditorComponent(table, value, isSelected, row, column);
    }
    
    Ho seguito la tua linea guida e ho aggiunto un metodo ne Match che mi ritorna il Conto vincente così da ritornare un Conto nel metodo getValueAt alla colonna 4... still don't work tho
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    Devuanx86_64 ha scritto:


    
    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (!(aValue instanceof Conto)) return;
        Conto conto = (Conto) aValue;
        listaMatch.get(rowIndex).setEsito(conto);
        aggiornaTabella();
    }
    
    public void aggiornaTabella() {
        this.fireTableStructureChanged();
    }
    Innanzitutto il setValueAt generalmente è molto "speculare" rispetto al getValueAt: si prende l'elemento i-esimo (il tuo Match al tal rowIndex), si fa lo switch (o catena if) su columnIndex, se 4 allora setti il conto.

    Il test con instanceof non è sbagliato ma sarebbe solo una precauzione in più. Ci si aspetta che alla colonna indice 4 l'oggetto sia un Conto. Se non lo è, allora è un baco (da correggere!).

    Inoltre fai un fireTableStructureChanged() che però è troppo "radicale" solo per aver aggiornato una cella. Vedi gli altri fireXXXX().


    Devuanx86_64 ha scritto:


    
    public class CellEditorComboConti extends DefaultCellEditor {
    Non c'è assolutamente bisogno di estendere DefaultCellEditor (a meno di dover fare cose davvero particolari).

    C'è l'esempio sul tutorial:
    JComboBox<Conto> comboBox = new JComboBox<>();
    // inserisci i tuoi oggetti Conto
    
    TableColumn column = ......
    column.setCellEditor(new DefaultCellEditor(comboBox));
    tutto lì.
  • Re: JComboBox in JTable con valori diversi a seconda della riga selezionata

    andbin ha scritto:


    Non c'è assolutamente bisogno di estendere DefaultCellEditor (a meno di dover fare cose davvero particolari).

    C'è l'esempio sul tutorial:
    JComboBox<Conto> comboBox = new JComboBox<>();
    // inserisci i tuoi oggetti Conto
    
    TableColumn column = ......
    column.setCellEditor(new DefaultCellEditor(comboBox));
    tutto lì.
    In che classe sarebbe opportuno effettuare questa operazione? essendo che i Conti listati nella comboBox devono cambiare a seconda della riga non potrei inserire questo codice in una classe qualsiasi immagino... mi sbaglio? Ma poi con

    andbin ha scritto:


    column.setCellEditor(new DefaultCellEditor(comboBox));
    non imposto una comboBox comune a tutte le rige per quella specifica colonna? In questo modo la lista dei conti non dipenderà più dalla riga e quindi dal match
Devi accedere o registrarti per scrivere nel forum
9 risposte