I am writing my own JMS Browser and I am struck at the JTable update of Messages from JMS servers. I have tried This below logis works , but its not updating realtime , means I would like to display each and every row added to Jtable immediately when its added from QueueBrowser to LinkedList.AbstractTableModel
TableModelListener
to make Jtable refresh when the data added into LinkedList.
I have updated the code as per the suggestions below.
Am I doing something wrong? can anyone help me ?
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();
}
}
and getting this exception.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
Is it wrong ?
To my knowledge, your JTable
should update automatically when a change to the TableModel
happens. Check out the sun tutorial on working with tables and specially the section on listening for data changes, this may help. That said, I have a couple of remarks:
I don't really get the
getValueAt(int row, int col)
method. Shouldn't you get the row-th message and the col-th attribute of the message?I'd add a
addRow(...)
andaddRows(...)
toMsgTable
implementation of TableModel to update the internal model and fire the appropriate event.You don't need to implement
TableModelListener
(I can't see any call toaddTableModelListener(...)
anyway)
(EDIT: The OP has updated his question with new code so I'm updating my answer accordingly below.)
You've modified the load(...)
signature and body to add a call to addTableModelListener(...)
and I think that both modifications are not correct.
About the addTableModelListener(...), the documentation says:
Adds a listener to the list that is notified each time a change to the data model occurs.
And about the various fireFooXxx(...)
methods:
Notifies all listeners that [a changed occurred]
So with the following implementation of a TableModelListener
:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
You'll end up making infinite recursive calls (the listener is notified by a change and fire an event that will notify him again etc), hence the java.lang.StackOverflowError.
Actually, I still think that you don't need a TableModelListener
(and the way you are registering it is not correct IMO, see Listening for Data Changes in the Sun tutorial). I'd thus remove the implements TableModelListener
and rather implement the load(...)
method like this:
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
A couple points to add for consideration:
- your
load(Enumeration e)
method does not need to throw aJMSException
, as you are just iterating over anEnumeration
. you should ensure that your firing of events is done within the EDT. This could be as simple as wrapping your call to
load
in a runnable and dropping it intoSwingUtilities.invokeLater()
:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
one way to up performance would be to only call fireTableDataChanged() at the end of the load() method, as opposed to after each line is loaded.
that should help.
ie:
void load(Enumeration e) throws JMSException {
while(e.hasMoreElements()){
queueList.add(e.nextElement());
fireTableDataChanged();
}
}
to
void load(Enumeration e) throws JMSException {
boolean dataAdded = false;
while(e.hasMoreElements()){
queueList.add(e.nextElement());
dataAdded = true;
}
fireTableDataChanged();
}
Well, the proper design is to create an addRow(...) method that receives a row of data and updates the internal storage of your TableModel. This method should then invoke the fileTableRowsInserted() method. Your getValueAt() method also makes no sense. According to your model you have 5 columns of data, yet you never check the column variable to return the proper column object.
Take a look at the source code of the DefaultTableModel to see how an insertRow() and getValueAt() method might be coded.
精彩评论