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)
間違っていますか?
解決
私の知る限り、 TableModel
が変更されると、 JTable
は自動的に更新されます。 テーブルの操作に関する太陽のチュートリアルをご覧ください。特に、データ変更のリスニングに関するセクション、これが役立つ場合があります。とは言うものの、私はいくつかのコメントがあります:
-
実際には
getValueAt(int row、int col)
メソッドを取得しません。行のメッセージとメッセージの列の属性を取得すべきではありませんか? -
addRow(...)
およびaddRows(...)
をTablecodeのMsgTable
実装に追加します内部モデルを更新し、適切なイベントを発生させます。 -
TableModelListener
を実装する必要はありません(とにかくaddTableModelListener(...)
の呼び出しが表示されません)
(編集:OPは彼の質問を新しいコードで更新したので、以下でそれに応じて回答を更新しています。)
load(...)
署名と本文を変更して addTableModelListener(...)
への呼び出しを追加しましたが、両方の変更はそうではないと思います正しい。
addTableModelListener(...について)、ドキュメントには次のように書かれています:
データモデルが変更されるたびに通知されるリストにリスナーを追加します。
そしてさまざまな fireFooXxx(...)
メソッドについて:
[変更が発生した]ことをすべてのリスナーに通知します
したがって、次の TableModelListener
の実装では:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
無限の再帰呼び出しを行うことになります(リスナーは変更によって通知され、再度通知するイベントを起動するなど)。したがって、 java.lang.StackOverflowError 。
実際には、 TableModelListener
は必要ないと思います(そして、登録方法は正しいIMOではありません。データ変更のリッスンをご覧ください)。したがって、 implements TableModelListener
を削除し、次のように load(...)
メソッドを実装します。
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
他のヒント
検討のために追加するカップルポイント:
-
load(Enumeration e)
メソッドは、Enumeration
を繰り返し処理するだけなので、JMSException
をスローする必要はありません。 -
イベントの発生がEDT内で行われるようにする必要があります。これは、実行可能コードで
load
への呼び出しをラップし、それをSwingUtilities.invokeLater()
にドロップするだけの簡単な方法です:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
パフォーマンスを向上させる1つの方法は、各行がロードされた後ではなく、load()メソッドの最後でのみfireTableDataChanged()を呼び出すことです。
それが役立つはずです。
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();
}
まあ、適切な設計は、データの行を受け取り、TableModelの内部ストレージを更新するaddRow(...)メソッドを作成することです。このメソッドは、fileTableRowsInserted()メソッドを呼び出す必要があります。 getValueAt()メソッドも意味がありません。モデルによると、5列のデータがありますが、適切な列オブジェクトを返すために列変数をチェックすることはありません。
defaultTableModelのソースコードを見て、insertRow()およびgetValueAt()メソッドのコーディング方法を確認してください。