简体   繁体   English

SwingWorker:在工作线程中创建Swing组件并添加EDT

[英]SwingWorker: creating Swing Components in worker thread and adding in EDT

According to the SwingWorker Javadoc: 根据SwingWorker Javadoc:

When writing a multi-threaded application using Swing, there are two constraints to keep in mind: 使用Swing编写多线程应用程序时,要牢记两个约束:

  • Time-consuming tasks should not be run on the Event Dispatch Thread. 耗时的任务不应在事件调度线程上运行。 Otherwise the application becomes unresponsive. 否则,应用程序将无响应。
  • Swing components should be accessed on the Event Dispatch Thread only. Swing组件应仅在事件调度线程上访问。

Thus, when using SwingWorker , we must access Swing Components only in done() and process() methods. 因此,在使用SwingWorker ,我们必须仅在done()process()方法中访问Swing组件。

So, I created a sample application which loads 3000 rows from database in chunks, each chunk with 50 rows and display it. 因此,我创建了一个示例应用程序,该应用程序从数据库中以块的形式加载3000行,每个块有50行并显示它。

SwingWorker<List<Person>, Person> worker = 
   new SwingWorker<List<Person>, Person>() {

      protected List<Person> doInBackground() {
         List<Person> data = new ArrayList<>();
         while (hasMoreData()) {
            List<Person> chunk = loadFiftyRows();
            data.addAll(chunk);
            publish(chunk);
         }
         return data;
      }

      protected void process(List<Person> chunks) {
         for (Person person : chunks) {
            container.add(createPanelFor(person));
         }
         container.revalidate();
         container.repaint();
      }

   };
worker.execute();

As, All swing access must be done on EDT, I am creating new JPanel instances for each person in the process() method. 由于所有摇摆访问都必须在EDT上完成,因此我正在为process()方法中的每个person创建新的JPanel实例。 But, still the application is quite heavy on start up. 但是,应用程序在启动时仍然很繁重。 It freezes and response to the events while the data is loading, is quite late. 它冻结并在加载数据时对事件做出响应,这已经很晚了。

Although, we are publishing 50 rows at a time, the chunk size gets bigger when process() method is invoked on EDT, sometimes 1000 rows. 尽管我们一次发布50行,但是在EDT上调用process()方法时,块大小会变大,有时会增加1000行。 I think this is the cause of the delay, creating 1000 instances of JPanel on EDT! 我认为这是延迟的原因,它在EDT上创建了1000个JPanel实例!

I feel, creating 1000 new instances of JPanel is also a quite heavy task, to be performed on EDT. 我感觉,要在EDT上执行1000个新的JPanel实例实例也是一项繁重的任务。 So, can't we create these JPanel instances in doInBackground() method, store it in a collection and then add those already created JPanel instances to the container in the process method? 因此,我们不能在doInBackground()方法中创建这些JPanel实例,将其存储在一个集合中,然后在process方法中将那些已经创建的JPanel实例添加到container中吗?

But, it will contradict the statement, "Swing components should be accessed on the Event Dispatch Thread only"! 但是,这将与“仅应在事件调度线程上访问Swing组件”这一说法相矛盾!

Does this statement mean, Existing Swing Components that have been added to the Swing Component Hierarchy and not newly created Swing Components? 此语句是否表示已添加到Swing组件层次结构中的现有Swing组件,而不是新创建的Swing组件?

Swing Threading Policy states: Swing线程策略状态:

In general Swing is not thread safe. 通常,Swing不是线程安全的。 All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread. 除非另有说明,否则所有Swing组件和相关类都必须在事件分发线程上进行访问。 Typical Swing applications do processing in response to an event generated from a user gesture. 典型的Swing应用程序会根据用户手势生成的事件进行处理。 For example, clicking on a JButton notifies all ActionListeners added to the JButton. 例如,单击JButton会通知添加到JButton的所有ActionListener。 As all events generated from a user gesture are dispatched on the event dispatching thread, most developers are not impacted by the restriction. 由于从用户手势生成的所有事件都分配在事件分配线程上,因此大多数开发人员不受此限制的影响。

Where the impact lies, however, is in constructing and showing a Swing application. 但是,影响所在在于构建和显示Swing应用程序。 Calls to an application's main method, or methods in Applet, are not invoked on the event dispatching thread. 在事件分配线程上不会调用对应用程序的主方法或Applet中的方法的调用。 As such, care must be taken to transfer control to the event dispatching thread when constructing and showing an application or applet. 因此,在构造和显示应用程序或小程序时,必须注意将控制权转移到事件分发线程。 The preferred way to transfer control and begin working with Swing is to use invokeLater. 转移控制权并开始使用Swing的首选方法是使用invokeLater。 The invokeLater method schedules a Runnable to be processed on the event dispatching thread. invokeLater方法可调度要在事件分配线程上处理的Runnable。

You shouldn't create Swing components outside the EventDispatchThread because updating a component's model generates events, more here . 您不应该在EventDispatchThread之外创建Swing组件,因为更新组件的模型会生成事件,更多信息请参见

To deepen this answer may be enlightening. 加深这个答案可能是有启发性的。

As mentioned in comment to your question "paging" and maybe a "loading bar" may solve your problem. 如对您的问题“分页”的评论中所述,也许“加载栏”可能会解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM