如何根据从其他线程中长时间运行的任务收到的通知来更新 JTable?
我有一个观察者表模型,它侦听在数据库中执行的一些更改,并且何时调用下面的更新方法。 我的问题是,我应该如何防止以下错误:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.set(ArrayList.java:337)
at com.mysimpatico.memoplatform.persistenceui.MeaningsViewerTopComponent$DefaultTableModelImpl.update(MeaningsViewerTopComponent.java:108)
我看不出 SwingWorker 有什么帮助。我在单独的线程中执行长时间运行的数据库任务,但这需要 Observable 类中的一个方法(数据库持久化)来通知观察者。
@Override
public void update(Observable o, final Object arg) {
final Meaning meng = (Meaning) arg;
final int row;
final boolean insert;
synchronized (mengs) {
if (mengs.contains(meng)) {
row = meng.getObjId();
mengs.set(row, meng);
insert = false;
} else {
row = mengs.size();
mengs.add(row, meng); //last
insert = true;
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
if (insert) {
fireTableRowsInserted(row, row);
} else {
fireTableRowsUpdated(row, row);
}
}
});
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
}
}
I've an Observer TableModel which listens to some changes, performed in the database, and when so the update method below is called.
My problem is, how should I prevent errors like:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.set(ArrayList.java:337)
at com.mysimpatico.memoplatform.persistenceui.MeaningsViewerTopComponent$DefaultTableModelImpl.update(MeaningsViewerTopComponent.java:108)
I don't see how SwingWorker would help. I've the long-running database task being performed in a separate thread, but this calls upon a method (database persisting) in an Observable class which notifies observers.
@Override
public void update(Observable o, final Object arg) {
final Meaning meng = (Meaning) arg;
final int row;
final boolean insert;
synchronized (mengs) {
if (mengs.contains(meng)) {
row = meng.getObjId();
mengs.set(row, meng);
insert = false;
} else {
row = mengs.size();
mengs.add(row, meng); //last
insert = true;
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
if (insert) {
fireTableRowsInserted(row, row);
} else {
fireTableRowsUpdated(row, row);
}
}
});
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尽管在事件调度线程上触发了插入/更新
TableModelEvent
,但实际上,您实际上是在执行数据库更新通知的线程上更新TableModel
。这很危险,因为它意味着:TableModel
。解决方案(理论上)应该只是将对
SwingUtilities.invokeAndWait
的调用移至以synchronized(mengs)
开头的代码块之外。此外,一旦完成此操作,您实际上可以完全删除同步关键字,因为对模型的所有访问都将在 EDT 上完成。顺便说一句,我会避免使用
Observer
/Observable
类(有关更多信息,请参阅我对 这个问题);定义特定于域的侦听器接口和事件类(即java.util.EventObject
子类)要好得多。Despite firing insert / update
TableModelEvent
s on the event dispatch thread you're actually updating theTableModel
on whichever thread is performing the notification of the database update. This is dangerous as it means:TableModel
in an inconsistent state.TableModel
as the notification thread is altering it.The solution should (in theory) simply be a case of moving your call to
SwingUtilities.invokeAndWait
to outside the block of code that begins:synchronized(mengs)
. Also, once you've done this you can actually removed the synchronized keyword entirely as all access to your model will be done on the EDT.As an aside I would avoid using the
Observer
/Observable
classes (for more information see my answer to this question); far better to define domain-specific listener interfaces and event classes (that subclassjava.util.EventObject
).你的索引正确吗?
上面的语句表示数组列表中只有一项。我无法判断您的代码是“添加”还是“更新”。但请记住,ResultSet 索引是从 1 开始的,而不是从 0 开始的,所以也许您需要从所有行值中减去 1?
Are your indexes correct?
The above statement says you only have one entry in the array list. I can't tell if your code is an "add" or an "update". But remember that ResultSet indexes are 1 based not 0 based so maybe you need to subtract 1 from all your row values?
一种选择是使用 org.jdesktop.application.Task。您需要将
TableModel
传递给任务,然后进行简单的TableModel.insert
调用。注意:任务只是线程的一个很好的包装。
One option is using a
org.jdesktop.application.Task
. You will need to pass theTableModel
to the Task and then so a simpleTableModel.insert
call.Note: The task is just a nice wrapper around a Thread.