Mise à jour de la file d'attente JMS vers JTable [Obtention d'une exception après chaque modification]
Question
J'écris mon propre navigateur JMS et je suis frappé par la mise à jour JTable des messages à partir des serveurs JMS. J'ai essayé Ce logis ci-dessous fonctionne, mais ne met pas à jour en temps réel, signifie I souhaite afficher chaque ligne ajoutée à Jtable immédiatement après son ajout de QueueBrowser à LinkedList. AbstractTableModel
TableModelListener
pour actualiser Jtable lorsque les données ajoutées à LinkedList.
J'ai mis à jour le code conformément aux suggestions ci-dessous.
Est-ce que je fais quelque chose de mal? quelqu'un peut-il m'aider?
QueueBrowser qb = session.createBrowser(q);
MsgTable mt = (MsgTable) queueTable.getModel();
mt.load(qb.getEnumeration(),mt);
qb.close();
class MsgTable extends AbstractTableModel implements TableModelListener{
final String[] columnNames = { "#", "Timestamp", "Type", "Mode",
"Priority" };
public void setRowSize(){
}
LinkedList queueList = new LinkedList();
public int getRowCount() { if (queueList == null) { return 0; } else { return queueList.size();}}
public int getColumnCount() { return columnNames.length;}
public String getColumnName(int column) {return columnNames[column];}
public Object getValueAt(int row, int column) {
if(queueList == null){
return null;
}
Message m = (Message) queueList.get(row);
...
}
void load(Enumeration e,MsgTable mt) {
mt.addTableModelListener(this);
while(e.hasMoreElements()){
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
Message getMessageAtRow(int row) {
if (queueList == null)
return null;
return ((Message) queueList.get(row));
}
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
}
et obtenir cette exception.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
Est-ce que c'est faux?
La solution
À ma connaissance, votre JTable
devrait se mettre à jour automatiquement lorsqu’une modification du TableModel
a lieu. Consultez le didacticiel Sun sur utiliser des tableaux et spécialement la section sur écouter les modifications de données , cela peut aider. Cela dit, j'ai quelques remarques à faire:
-
Je ne comprends pas vraiment la méthode
getValueAt (int row, int col)
. Ne devriez-vous pas obtenir le message de la ligne-ème et l'attribut de la colonne de la message? -
Je voudrais ajouter un
addRow (...)
etaddRows (...)
àMsgTable
implémentation de TableModel mettre à jour le modèle interne et déclencher l'événement approprié. -
Vous n'avez pas besoin d'implémenter
TableModelListener
(je ne vois aucun appel àaddTableModelListener (...)
de toute façon)
(EDIT: le PO a mis à jour sa question avec le nouveau code, donc je mets à jour ma réponse en conséquence ci-dessous.)
Vous avez modifié la signature et le corps de load (...)
pour ajouter un appel à addTableModelListener (...)
et je pense que les deux modifications ne sont pas correct.
À propos de la addTableModelListener (... ) , la documentation indique:
Ajoute un écouteur à la liste, lequel est averti à chaque modification du modèle de données.
Et à propos des différentes méthodes fireFooXxx (...)
:
Notifie tous les écouteurs que [un changement a eu lieu]
Donc, avec l'implémentation suivante d'un TableModelListener
:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
Vous finirez par faire des appels récursifs infinis (l'auditeur est averti par un changement et déclenche un événement qui le notifiera à nouveau, etc.), d'où le java.lang.StackOverflowError .
En fait, je pense toujours que vous n’avez pas besoin d’un TableModelListener
(et que la façon dont vous vous enregistrez n’est pas une bonne OMI, voir Écoute des modifications de données dans le didacticiel Sun). Je supprimerais donc le implémentant TableModelListener
et mettrais plutôt en œuvre la méthode load (...)
comme ceci:
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
Autres conseils
Quelques points à ajouter pour examen:
- votre méthode
load (énumération e)
n'a pas besoin de générer uneexception JMS
, car vous ne faites qu'itérer sur uneénumération
. -
vous devez vous assurer que les événements sont déclenchés dans l’EDT. Cela pourrait être aussi simple que d'encapsuler votre appel à
load
dans un exécutable et de le déposer dansSwingUtilities.invokeLater ()
:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
Pour augmenter les performances, il suffit d'appeler fireTableDataChanged () à la fin de la méthode load (), et non après le chargement de chaque ligne.
cela devrait aider.
c'est-à-dire:
void load(Enumeration e) throws JMSException {
while(e.hasMoreElements()){
queueList.add(e.nextElement());
fireTableDataChanged();
}
}
à
void load(Enumeration e) throws JMSException {
boolean dataAdded = false;
while(e.hasMoreElements()){
queueList.add(e.nextElement());
dataAdded = true;
}
fireTableDataChanged();
}
La conception appropriée consiste à créer une méthode addRow (...) qui reçoit une ligne de données et met à jour le stockage interne de votre TableModel. Cette méthode doit ensuite invoquer la méthode fileTableRowsInserted (). Votre méthode getValueAt () n’a également aucun sens. Selon votre modèle, vous avez 5 colonnes de données, mais vous ne cochez jamais la variable de colonne pour renvoyer le bon objet de colonne.
Examinez le code source de DefaultTableModel pour voir comment une méthode insertRow () et getValueAt () peut être codée.