JMS 队列到 JTable 更新 [现在在更改后出现异常]
题
我正在编写自己的 JMS 浏览器,并且对来自 JMS 服务器的消息的 JTable 更新感到震惊。 我努力了 下面的逻辑有效,但它不实时更新,这意味着我想在从 QueueBrowser 添加到 LinkedList 时立即显示添加到 Jtable 的每一行。AbstractTableModel
TableModelListener
当数据添加到LinkedList时使Jtable刷新。
我已根据以下建议更新了代码。
难道我做错了什么?谁能帮我 ?
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
发生。查看太阳教程 使用表格 特别是关于 监听数据变化, ,这可能有帮助。话虽如此,我有几点评论:
我真的不明白
getValueAt(int row, int col)
方法。难道您不应该获取该消息的第 row 消息和 col-th 属性吗?我想添加一个
addRow(...)
和addRows(...)
到MsgTable
实现 TableModel 来更新内部模型并触发适当的事件。你不需要实施
TableModelListener
(我看不到任何呼叫addTableModelListener(...)
反正)
(编辑:OP已经用新代码更新了他的问题,所以我在下面相应地更新了我的答案。)
您已经修改了 load(...)
添加调用的签名和正文 addTableModelListener(...)
我认为这两种修改都是不正确的。
有关 添加TableModelListener(...), ,文档说:
将侦听器添加到每次数据模型发生更改时收到通知的列表。
而关于各种 fireFooXxx(...)
方法:
通知所有侦听器[发生了更改]
因此,通过以下实现 TableModelListener
:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
您最终将进行无限递归调用(监听器收到更改通知并触发一个事件再次通知他等),因此 java.lang.StackOverflowError 错误.
其实我还是觉得你不需要 TableModelListener
(并且您注册的方式在我看来是不正确的,请参阅 监听数据变化 在 Sun 教程中)。因此我会删除 implements TableModelListener
而是实施 load(...)
像这样的方法:
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
其他提示
需要补充几点供考虑:
- 你的
load(Enumeration e)
方法不需要抛出JMSException
, ,因为您只是迭代Enumeration
. 您应该确保您的事件触发是在 EDT 内完成的。这可能就像将您的呼叫包装到
load
在可运行的并将其放入SwingUtilities.invokeLater()
:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
提高性能的一种方法是仅在load()方法结束时调用fireTableDataChanged(),而不是在每行加载之后调用。
应该有所帮助。
即:
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()方法的编码方式。