如何根据从其他线程中长时间运行的任务收到的​​通知来更新 JTable?

发布于 2024-09-29 11:22:39 字数 1699 浏览 6 评论 0原文

我有一个观察者表模型,它侦听在数据库中执行的一些更改,并且何时调用下面的更新方法。 我的问题是,我应该如何防止以下错误:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

过期以后 2024-10-06 11:22:39

尽管在事件调度线程上触发了插入/更新TableModelEvent,但实际上,您实际上是在执行数据库更新通知的线程上更新TableModel。这很危险,因为它意味着:

  • 事件调度线程可能会看到处于不一致状态的 TableModel
  • 当通知线程更改 TableModel 时,事件调度线程可能会尝试呈现它。

解决方案(理论上)应该只是将对 SwingUtilities.invokeAndWait 的调用移至以 synchronized(mengs) 开头的代码块之外。此外,一旦完成此操作,您实际上可以完全删除同步关键字,因为对模型的所有访问都将在 EDT 上完成。

顺便说一句,我会避免使用 Observer / Observable 类(有关更多信息,请参阅我对 这个问题);定义特定于域的侦听器接口和事件类(即 java.util.EventObject 子类)要好得多。

Despite firing insert / update TableModelEvents on the event dispatch thread you're actually updating the TableModel on whichever thread is performing the notification of the database update. This is dangerous as it means:

  • The event dispatch thread could potential see the TableModel in an inconsistent state.
  • The event dispatch thread could be attempting to render the 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 subclass java.util.EventObject).

享受孤独 2024-10-06 11:22:39

你的索引正确吗?

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 

上面的语句表示数组列表中只有一项。我无法判断您的代码是“添加”还是“更新”。但请记住,ResultSet 索引是从 1 开始的,而不是从 0 开始的,所以也许您需要从所有行值中减去 1?

Are your indexes correct?

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 

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?

我ぃ本無心為│何有愛 2024-10-06 11:22:39

一种选择是使用 org.jdesktop.application.Task。您需要将 TableModel 传递给任务,然后进行简单的 TableModel.insert 调用。

注意:任务只是线程的一个很好的包装。

One option is using a org.jdesktop.application.Task. You will need to pass the TableModel to the Task and then so a simple TableModel.insert call.

Note: The task is just a nice wrapper around a Thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文