tags:

views:

309

answers:

4

I am writing my own JMS Browser and I am struck at the JTable update of Messages from JMS servers. I have tried AbstractTableModel TableModelListener to make Jtable refresh when the data added into LinkedList. 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.

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 ?

A: 

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();

        }
Jill Renee
I agreed , but I want to update the Jtable at the moment the new data added into the list.
TuxGeek
A: 

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.

camickr
+1  A: 

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(...) and addRows(...) to MsgTable 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 to addTableModelListener(...) 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();   
}
Pascal Thivent
Thanks Pascal. This makes sense, Let me check it and come back.
TuxGeek
+1  A: 

A couple points to add for consideration:

  • your load(Enumeration e) method does not need to throw a JMSException, as you are just iterating over an Enumeration.
  • 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 into SwingUtilities.invokeLater() :

    MsgTable mt = (MsgTable) queueTable.getModel();
    final Enumeration e = qb.getEnumeration();
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            mt.load(e);
        }
    });
    
akf