JMS Queue to JTable Update [Ahora obteniendo una excepción después de los cambios]
Pregunta
Estoy escribiendo mi propio navegador JMS y estoy sorprendido por la actualización de JTable de Mensajes desde los servidores JMS. He intentado Este logis a continuación funciona, pero no se actualiza en tiempo real, significa que quisiera mostrar todas y cada una de las filas agregadas a Jtable inmediatamente cuando se agrega de QueueBrowser a LinkedList. AbstractTableModel
TableModelListener
para actualizar Jtable cuando se agregan los datos en LinkedList.
He actualizado el código según las sugerencias a continuación.
¿Estoy haciendo algo mal? ¿Alguien me puede ayudar?
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();
}
}
y obteniendo esta excepción.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
¿Está mal?
Solución
Según mi conocimiento, su JTable
debería actualizarse automáticamente cuando ocurra un cambio en el TableModel
. Consulte el tutorial de sun en trabajo con tablas y especialmente la sección sobre escuchar cambios de datos , esto puede ayudar. Dicho esto, tengo un par de comentarios:
-
Realmente no obtengo el método
getValueAt (int row, int col)
. ¿No debería obtener el mensaje de la fila y el atributo de la columna del mensaje? -
Yo agregaría un
addRow (...)
yaddRows (...)
a la implementación deMsgTable
de TableModel para actualizar el modelo interno y activar el evento apropiado. -
No necesita implementar
TableModelListener
(no puedo ver ninguna llamada aaddTableModelListener (...)
de todos modos)
(EDITAR: El OP ha actualizado su pregunta con un nuevo código, por lo que estoy actualizando mi respuesta según corresponda a continuación).
Ha modificado la firma load (...)
y el cuerpo para agregar una llamada a addTableModelListener (...)
y creo que ambas modificaciones no son correcto.
Acerca de addTableModelListener (... ) , la documentación dice:
Agrega un oyente a la lista que recibe una notificación cada vez que se produce un cambio en el modelo de datos.
Y sobre los diversos métodos fireFooXxx (...)
:
Notifica a todos los oyentes que [ocurrió un cambio]
Entonces, con la siguiente implementación de un TableModelListener
:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
Terminarás haciendo infinitas llamadas recursivas (se notifica al oyente mediante un cambio y se activa un evento que le notificará nuevamente, etc.), por lo tanto, java.lang.StackOverflowError .
En realidad, sigo pensando que no necesita un TableModelListener
(y la forma en que se está registrando no es la IMO correcta, consulte Escuchar cambios de datos en el tutorial de Sun). Por lo tanto, eliminaría los implementos TableModelListener
y más bien implementaría el método load (...)
como este:
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
Otros consejos
Un par de puntos para agregar para consideración:
- su método de
load (Enumeration e)
no necesita lanzar unaJMSException
, ya que solo está iterando sobre unaEnumeration
. -
debe asegurarse de que su activación de eventos se realice dentro de la EDT. Esto podría ser tan simple como ajustar su llamada a
load
en un runnable y soltarla enSwingUtilities.invokeLater ()
:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
una forma de mejorar el rendimiento sería llamar solo a fireTableDataChanged () al final del método load (), a diferencia de después de cargar cada línea.
eso debería ayudar.
es decir:
void load(Enumeration e) throws JMSException {
while(e.hasMoreElements()){
queueList.add(e.nextElement());
fireTableDataChanged();
}
}
a
void load(Enumeration e) throws JMSException {
boolean dataAdded = false;
while(e.hasMoreElements()){
queueList.add(e.nextElement());
dataAdded = true;
}
fireTableDataChanged();
}
Bueno, el diseño adecuado es crear un método addRow (...) que reciba una fila de datos y actualice el almacenamiento interno de su TableModel. Este método debería invocar el método fileTableRowsInserted (). Su método getValueAt () tampoco tiene sentido. Según su modelo, tiene 5 columnas de datos, sin embargo, nunca verifica la variable de columna para devolver el objeto de columna adecuado.
Eche un vistazo al código fuente de DefaultTableModel para ver cómo se pueden codificar los métodos insertRow () y getValueAt ().