PDA

Visualizza la versione completa : [Java] Strano problema con JTable


lelebug
24-03-2005, 17:19
Ciao a tutti!
Ho un problema molto strano con una JTable.
La cosa è abbastanza complicata quindi spero di riuscire a spiegarlo il meglio possibile.

Sto implementato una classe estensione della JTable che prende i dati da visualizzare da una tabella di un database MySql attraverso l'esecuzione di una query passata come parametro.
Fin qui nessun problema, la classe funziona correttamente e senza problemi.

Ora vorrei estendere questa classe per consentire anche la modifica e l'inserimento di righe, non direttamente dalla JTable ma attraverso l'apertura di una JDialog.

Io ho pensato di fare in questo modo:
- Il ResultSet che creo nella mia classe estensione della JTable è un UpdatableResultSet
- Sempre nella JTable inserisco un ListSelectionListener e faccio in modo che al cambiamento della riga corrente della JTable venga modificata anche la riga del ResultSet
- Infine quando l'utente clicca con il tasto destro sopra la JTable e sceglie la voce menu "Modifica" (ho creato un JPopupMenu) venga istanziata una JDialog a cui passo il riferimento al ResultSet creato dalla tabella e posizionato alla riga corrispondente la riga selezionata nella JTable.

In questo modo quando viene aperta la finestra di dialogo mi dovrei trovare il riferimento al ResultSet già posizionata sulla riga selezionata e quindi potrei apportare le modifiche direttamente su quel ResultSet attraverso i metodi updateXXX dell'UpdatableResultSet.

Tutto ok se non fosse per il fatto che inspiegabilmente quando scatta l'evento ActionEvent del JPopupMenu quindi al momento di passare il riferimento al ResultSet alla finestra di dialogo il cursore del ResultSet è posizionato sull'ultima riga.

Non so se sono riuscito a farmi capire comunque adesso per fare un po' di chiarezza posto anche due righe di codice magari si capisce meglio:

Questo è il codice che aggiunge il ListSelectionListener alla tabella e "sincronizza" la posizione del cursore del ResultSet alla posizione della riga della tabella:


private void initialize() {
// aggiungo il ListSelectionListener
this.setSelectionMode(ListSelectionModel.SINGLE_SE LECTION);
ListSelectionModel rowSM = this.getSelectionModel();
rowSM.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
ListSelectionModel lsm = (ListSelectionModel)evt.getSource();
if (!lsm.isSelectionEmpty() && !evt.getValueIsAdjusting()) {
int row = lsm.getMinSelectionIndex();
dataTableModel.moveRsCursorToRow(row);
}
}
});
}


Questo è la funzione moveRsCursorToRow del modello della tabella


public void moveRsCursorToRow(int rowIndex) {
if (rs != null) {
try {
rs.absolute(rowIndex + 1);
currentRow = rs.getRow();
// Qui mi stampa la riga giusta (cioè quella selezionata nella JTable)
System.out.println("Riga corrent: " + rs.getRow());
} catch (SQLException e) {
new JErrorMessage(e);
}
}
}


Infine questo è il JPopupMenu che apre la finestra di dialogo per la modifica della riga selezionata


class ContextualMenu extends JPopupMenu implements ActionListener {
private JMenuItem nuovo = null, modifica = null, elimina = null;

public ContextualMenu() {
nuovo = new JMenuItem("Nuovo");
nuovo.addActionListener(this);
modifica = new JMenuItem("Modifica");
modifica.addActionListener(this);
elimina = new JMenuItem("Elimina");
elimina.addActionListener(this);

this.add(nuovo);
this.add(modifica);
this.add(elimina);
}

/**** Implemetazione interfaccia ActionListener ****/
public void actionPerformed(ActionEvent evt) {
if (evt.getActionCommand().equals("Nuovo")) {
try {
DialogPopup popup = (DialogPopup)Class.forName(dialog).newInstance();
((DataTableModel)dataTableModel).getResultSet().mo veToInsertRow();
popup.setResultSet(((DataTableModel)dataTableModel ).getResultSet());
((JDialog)popup).setVisible(true);
} catch (Exception e) {
new JErrorMessage(e);
}
}
else if (evt.getActionCommand().equals("Modifica")) {
try {
DialogPopup popup = (DialogPopup)Class.forName(dialog).newInstance();
// In questo punto sulla console mi stampa l'ultima riga anzichè quella selezionata
System.out.print("Riga corrente: " + ((DataTableModel)dataTableModel).getResultSet().ge tRow());
// Passo il riferimento al ResultSet alla finestra di dialogo aperta
popup.setResultSet(((DataTableModel)dataTableModel ).getResultSet());
((JDialog)popup).setVisible(true);
} catch (Exception e) {
new JErrorMessage(e);
}
}
}
/**** Fine Implemetazione interfaccia ActionListener ****/

}


Grazie a tutti quelli che avranno voglia di aiutarmi :ciauz:

dekdek
24-03-2005, 17:56
Uhm, troppe classi di cui ignoro l'utilizzo.
Cmq, nel mio piccolo mi e' successo qualcosa di vagamente simile con un JComboBox.
La causa era che avevo fatto l'override di actionPerformed, non sapendo che il Combo Box gia' implementava ActionListener: me ne sono accorto perche' NetBeans affianca un'icona diversa in questo caso...
La soluzione, ovviamente: spostare il tutto in una classe separata.

lelebug
25-03-2005, 09:29
Innanzitutto grazie per la risposta.
Anche se in realtà i listener che avevo implementato internamente alle mie classi non erano già implementati nelle loro rispettive superclassi ho provato utilizzare dei listener esterni la classe ma purtroppo il problema c'è ancora.
Per il momento ho risolto memorizzando il numero di riga selezionata alla chiamata del metodo moveRsCursorToRow in modo che quando il ResultSet viene passato alla finestra di dialogo riposiziono il cursore su quella riga, ma sto comunque incontrando un innumerevole serie di problemi e probabilmente dovrò abbandonare questa idea e procedere in qualche altro modo :messner:. Peccato perchè non mi sembrava tanto malvagia idea (modestamente parlando :D ).
Comunque se ti viene qualche idea fammi sapere.

Grazie mille
:ciauz:

dekdek
25-03-2005, 09:49
Un bel trace in profondita' per vedere dove si manifesta il problema? :master:

lelebug
25-03-2005, 10:14
Il problema è che non mi da nessun tipo di errore, ma semplicemente prima di passare il ResultSet alla finestra di dialogo questo (il ResultSet) si posiziona sull'ultima riga anzichè rimanere fermo sulla riga settata in precedenza. Credimi, le ho provate davvero tutte prima di chiedere aiuto al forum.

Ciao :ciauz:

dekdek
25-03-2005, 10:27
Durante il debug puoi fare un watch su questa espressione che hai usato anche nel codice:



((DataTableModel)dataTableModel).getResultSet().ge tRow()


sempre che ci sia visibilita' di dataTableModel...
Ci dovra' essere un momento in cui passa dal valore giusto a quello sbagliato. Se parte gia' col valore sbagliato...

Cmq non ti voglio far perdere troppo tempo appresso a me, visto che, come ti ho detto, non conosco parte delle classi che usi, quindi sto andando ad intuito...

lelebug
25-03-2005, 10:44
Apparentemente non c'è niente che vada a modificare il cursore del ResultSet perchè l'unica cosa che lo modifica e la selezione di una nuova riga della tabella da parte dell'utente (ListSelectionListener). Ho anche messo un breakpoint con debug nel metodo valueChanged del ListSelectionListener per vedere se in qualche modo scattava questo evento da solo senza che l'utente si posizioni sull'ultima riga, ma sembra non scattare. Quindi non c'è proprio niente che modifichi lo stato del cursore.

Comunque come ti ho detto nel post precedente avevo risolto passando anche il numero di riga del ResultSet in modo da forzare il posizionamento del cursore alla riga giusta prima di passarlo alla dialog e così va, però mi succede un'altra cosa molto strana: quando clicco su modifica si apre la finestra di dialogo con i dati della riga selezionata e il cursore del ResultSet è posizionato correttamente, se non tocco la finestra di dialogo, modifico i dati e salvo tutto ok, ma appena sposto la finestra di dialogo il cursore del ResultSet si riposiziona sull'ultima riga. Sicuramente ci sarà qualche evento che fa fare qualche refresh della JTable però non so proprio più dove andare a mettere le mani, anche perchè anch'io non ho grossa esperienza in Java e si può dire che questi siano i miei primi tentativi "seri" con questo linguaggio.
Aiutatemi vi prego! non so più dove sbattere la testa :dhò:

Grazie
Ciao

lelebug
25-03-2005, 11:08
Ho trovato!!!
Il problema era nell'implementazione del metodo getValueAt dell'interfaccia TableModel. In pratica per prendere il valore della colonna spostavo il cursore del ResultSet sulla riga passata come argomento e poi non lo riposizionavo sulla riga corrente, per cui quando veniva fatto un refresh della tabella veniva chiamato questo metodo per tutte le righe / colonne della tabella dopodichè ovviamente il cursore rimaneva sull'ultima riga. Riposizionando il cursore sulla riga corretta dopo aver letto il valore del campo ho risolto il problema.

Grazie mille dekdek per l'aiuto.
Ciao
:ciauz:

dekdek
25-03-2005, 11:53
:ciauz:

Loading