Очередь JMS для обновления JTable [Теперь получаем исключение после изменений]
Вопрос
Я пишу свой собственный браузер JMS, и я поражен обновлением JTable сообщений с серверов JMS. Я пытался Приведенный ниже логис работает, но он не обновляется в режиме реального времени, что означает, что я хотел бы отображать каждую строку, добавленную в Jtable, сразу после ее добавления из QueueBrowser в LinkedList.AbstractTableModel
TableModelListener
чтобы Jtable обновлялся при добавлении данных в LinkedList.
Я обновил код в соответствии с приведенными ниже предложениями.
Я делаю что-то не так?кто - нибудь может мне помочь ?
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();
}
}
и получаю это исключение.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
Это неправильно ?
Решение
Насколько мне известно, ваш JTable
должен обновляться автоматически при изменении TableModel
случается.Ознакомьтесь с руководством sun по работа с таблицами и особенно раздел, посвященный прослушивание изменений данных, это может помочь.Тем не менее, у меня есть пара замечаний:
Я действительно не понимаю
getValueAt(int row, int col)
способ.Разве вы не должны получить сообщение row-th и атрибут col-th сообщения?Я бы добавил
addRow(...)
иaddRows(...)
ДляMsgTable
реализация TableModel для обновления внутренней модели и запуска соответствующего события.Вам не нужно внедрять
TableModelListener
(Я не вижу никакого призыва кaddTableModelListener(...)
в любом случае)
(РЕДАКТИРОВАТЬ:OP обновил свой вопрос новым кодом, поэтому я соответствующим образом обновляю свой ответ ниже.)
Вы изменили load(...)
подпись и текст для добавления вызова addTableModelListener(...)
и я думаю, что обе модификации неверны.
О том, что addTableModelListener(...), в документации говорится:
Добавляет прослушиватель в список, который получает уведомление каждый раз, когда происходит изменение модели данных.
И о различных fireFooXxx(...)
методы:
Уведомляет всех слушателей о том, что [произошло изменение]
Итак, при следующей реализации a TableModelListener
:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
В конечном итоге вы будете выполнять бесконечные рекурсивные вызовы (слушатель получает уведомление об изменении и запускает событие, которое уведомит его снова и т.д.), Следовательно, java.lang.StackOverflowError.
На самом деле, я все еще думаю, что тебе не нужен TableModelListener
(и способ, которым вы это регистрируете, неверен, IMO, см. Прослушивание изменений данных в учебном пособии Sun).Таким образом, я бы удалил implements TableModelListener
и скорее реализуйте load(...)
метод, подобный этому:
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
Другие советы
Хочу добавить пару моментов для рассмотрения:
- твой
load(Enumeration e)
методу не нужно выбрасыватьJMSException
, поскольку вы просто повторяетеEnumeration
. вы должны убедиться, что запуск событий выполняется в рамках EDT.Это может быть так же просто, как обернуть ваш вызов в
load
в runnable и помещаем его вSwingUtilities.invokeLater()
:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
одним из способов повышения производительности было бы вызывать fireTableDataChanged() только в конце метода load(), в отличие от после загрузки каждой строки.
это должно помочь.
т. е.:
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();
}
Что ж, правильный дизайн - создать метод addRow (...), который получает строку данных и обновляет внутреннее хранилище вашей TableModel. Этот метод должен затем вызвать метод fileTableRowsInserted (). Ваш метод getValueAt () также не имеет смысла. Согласно вашей модели у вас есть 5 столбцов данных, но вы никогда не проверяете переменную столбца, чтобы получить правильный объект столбца.
Взгляните на исходный код DefaultTableModel, чтобы увидеть, как могут быть закодированы методы insertRow () и getValueAt ().