如果要使用Swing用J​​ava编写桌面或Java Web Start程序,您可能会觉得需要通过创建自己的线程在后台运行某些东西。

没有什么可以阻止您在Swing中使用标准的多线程技术,并且需要遵循通常的注意事项。 如果您有多个线程访问相同的变量,则需要使用同步方法或代码块(或诸如AtomicInteger或ArrayBlockingQueue之类的线程安全类)。

但是,对于那些粗心的人来说是一个陷阱。 与大多数用户界面API一样,您无法从自己创建的线程更新用户界面。 好吧,正如每个Java本科生都知道的那样,您通常可以 ,但是您不应该。 如果这样做,有时您的程序会运行,而其他时候则无法。

您可以通过使用专门的SwingWorker类来解决此问题。 在本文中,我将向您展示即使您正在使用Thread类,如何使程序正常运行,然后我们将继续研究SwingWorker解决方案。

为了演示,我创建了一个Swing程序。

如您所见,它由两个标签和一个开始按钮组成。 此刻,单击开始按钮将调用一个不执行任何操作的处理程序方法。 这是Java代码:

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.concurrent.ExecutionException;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;public class MainFrame extends JFrame {private JLabel countLabel1 = new JLabel('0');private JLabel statusLabel = new JLabel('Task not completed.');private JButton startButton = new JButton('Start');public MainFrame(String title) {super(title);setLayout(new GridBagLayout());countLabel1.setFont(new Font('serif', Font.BOLD, 28));GridBagConstraints gc = new GridBagConstraints();gc.fill = GridBagConstraints.NONE;gc.gridx = 0;gc.gridy = 0;gc.weightx = 1;gc.weighty = 1;add(countLabel1, gc);gc.gridx = 0;gc.gridy = 1;gc.weightx = 1;gc.weighty = 1;add(statusLabel, gc);gc.gridx = 0;gc.gridy = 2;gc.weightx = 1;gc.weighty = 1;add(startButton, gc);startButton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent arg0) {start();}});setSize(200, 400);setDefaultCloseOperation(EXIT_ON_CLOSE);setVisible(true);}private void start() {}public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {new MainFrame('SwingWorker Demo');}});}
}

我们将添加一些代码到start()方法中,以响应单击开始按钮而调用。

首先让我们尝试一个普通线程。

private void start() {Thread worker = new Thread() {public void run() {// Simulate doing something useful.for(int i=0; i<=10; i++) {// Bad practicecountLabel1.setText(Integer.toString(i));try {Thread.sleep(1000);} catch (InterruptedException e) {}}// Bad practicestatusLabel.setText('Completed.');}};worker.start();}

实际上,此代码似乎有效(至少对我而言)。 该程序最终看起来像这样:

但是,不建议您这样做。 我们正在从自己的线程中更新GUI,在某些情况下,这肯定会引发异常。

如果要从另一个线程更新GUI,则应使用SwingUtilities安排更新代码在事件分发线程上运行。

以下代码很好,但像恶魔本人一样丑陋。

private void start() {Thread worker = new Thread() {public void run() {// Simulate doing something useful.for(int i=0; i<=10; i++) {final int count = i;SwingUtilities.invokeLater(new Runnable() {public void run() {countLabel1.setText(Integer.toString(count));}});try {Thread.sleep(1000);} catch (InterruptedException e) {}}SwingUtilities.invokeLater(new Runnable() {public void run() {statusLabel.setText('Completed.');}});}};worker.start();}

当然,必须做些什么使我们的代码更优雅?

SwingWorker类

SwingWorker是使用Thread class (专门为Swing设计)的替代方法。 这是一个抽象类,它带有两个模板参数,这使它看起来非常凶猛,并使大多数人不愿使用它。 但是实际上,它并不像看起来那样复杂。

让我们看一些仅运行后台线程的代码。 对于第一个示例,我们将不使用任何一个模板参数,因此将它们都设置为Void ,这是Java的等效于原始void类型的类(带有小写的“ v”)。

运行后台任务

通过实现doInBackground方法并调用execute来运行代码,我们可以在后台运行任务。

SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {@Overrideprotected Void doInBackground() throws Exception {// Simulate doing something useful.for (int i = 0; i <= 10; i++) {Thread.sleep(1000);System.out.println('Running ' + i);}return null;}};worker.execute();

请注意, SwingWorker是一站式服务,因此,如果我们想再次运行代码,则需要创建另一个SwingWorker ; 您无法重新启动同一台。

很简单,嘿? 但是,如果我们想在运行代码后以某种状态更新GUI,该怎么办? 您无法从doInBackground更新GUI,因为它不在主事件分配线程中运行。

但是有一个解决方案。 我们需要利用第一个模板参数。

线程完成后更新GUI

我们可以通过从doInBackground()返回一个值,然后doInBackground() done()来更新GUI,从而可以安全地更新GUI。 我们使用get()方法检索从doInBackground()返回的值

因此,第一个模板参数确定doInBackground()get()的返回类型。

SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {@Overrideprotected Boolean doInBackground() throws Exception {// Simulate doing something useful.for (int i = 0; i <= 10; i++) {Thread.sleep(1000);System.out.println('Running ' + i);}// Here we can return some object of whatever type// we specified for the first template parameter.// (in this case we're auto-boxing 'true').return true;}// Can safely update the GUI from this method.protected void done() {boolean status;try {// Retrieve the return value of doInBackground.status = get();statusLabel.setText('Completed with status: ' + status);} catch (InterruptedException e) {// This is thrown if the thread's interrupted.} catch (ExecutionException e) {// This is thrown if we throw an exception// from doInBackground.}}};worker.execute();

如果我们要在进行过程中更新GUI怎么办? 这就是第二个模板参数的用途。

从正在运行的线程更新GUI

要从正在运行的线程更新GUI,我们使用第二个模板参数。 我们调用publish()方法来“发布”我们要用来更新用户界面的值(可以是第二个模板参数指定的任何类型)。 然后,我们重写process()方法,该方法接收我们发布的值。

实际上process()接收已发布值的列表,因为在实际调用process()之前可能会发布多个值。

在此示例中,我们只是将最新值发布到用户界面。

SwingWorker<Boolean, Integer> worker = new SwingWorker<Boolean, Integer>() {@Overrideprotected Boolean doInBackground() throws Exception {// Simulate doing something useful.for (int i = 0; i <= 10; i++) {Thread.sleep(1000);// The type we pass to publish() is determined// by the second template parameter.publish(i);}// Here we can return some object of whatever type// we specified for the first template parameter.// (in this case we're auto-boxing 'true').return true;}// Can safely update the GUI from this method.protected void done() {boolean status;try {// Retrieve the return value of doInBackground.status = get();statusLabel.setText('Completed with status: ' + status);} catch (InterruptedException e) {// This is thrown if the thread's interrupted.} catch (ExecutionException e) {// This is thrown if we throw an exception// from doInBackground.}}@Override// Can safely update the GUI from this method.protected void process(List<Integer> chunks) {// Here we receive the values that we publish().// They may come grouped in chunks.int mostRecentValue = chunks.get(chunks.size()-1);countLabel1.setText(Integer.toString(mostRecentValue));}};worker.execute();

我希望您喜欢这个对高度有用的SwingWorker类的介绍。

您可以在我的网站Cave of Programming中找到更多教程,包括有关多线程的完整免费视频课程以及有关Swing,Android和Servlets 的课程 。

参考:来自Java出现日历博客的JCG合作伙伴 John Purcell的SwingWorker与Java Swing中的多线程 。

翻译自: https://www.javacodegeeks.com/2012/12/multi-threading-in-java-swing-with-swingworker.html

使用SwingWorker的Java Swing中的多线程相关推荐

  1. swingworker_使用SwingWorker的Java Swing中的多线程

    swingworker 如果要使用Swing用J​​ava编写桌面或Java Web Start程序,您可能会觉得需要通过创建自己的线程在后台运行某些程序. 没有什么可以阻止您在Swing中使用标准的 ...

  2. Java 程序中的多线程

    在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...

  3. Java Swing中的聊天气泡

    本文将向您解释"如何在Java swing应用程序中绘制聊天气泡?" 聊天气泡与呼出气泡或思想气泡相同. 今天,大多数聊天应用程序都以这种格式显示转换,因此本文将帮助您在用Java ...

  4. java swing 注册事件_比较Java Swing中三种注册事件的方法

    Swing 是目前Java中不可缺少的窗口工具组,是建立图形化用户界面(GUI)程序的强大工具.Java Swing组件自动产生各种事件来响应用户行为.Java将事件封装成事件类,并且为每个事件类定义 ...

  5. Java Swing中键盘事件的处理

    在Java Swing编程过程中,经常需要处理键盘事件,例如处理快捷键等.这里就介绍如何定义键盘事件,以及如何处理这些事件. 在jdk1.2中,分别针对Jcomponent和Text类的对象定制了不同 ...

  6. Java Swing中JFreeChart构建双纵轴(双Y轴)图表的使用纪要

    背景 项目应用中整理纪要,用于参数说明.后抽部分简码以用例,特此纪要! 问题 Java Swing中JFreeChart如何构建双纵轴(双Y轴)图表 说明 JFreeChart是一个工厂类,是Swin ...

  7. JAVA Swing 中的表格

    今天我们来学习一下java swing中的表格怎么来使用 在用swing技术开发系统的时候, 有时候会需要用到表格,那么我们来看看表格是怎么使用的 public class Table1 extend ...

  8. Java 并发编程解析 | 如何正确理解Java领域中的多线程模型,主要用来解决什么问题?

    苍穹之边,浩瀚之挚,眰恦之美: 悟心悟性,善始善终,惟善惟道! -- 朝槿<朝槿兮年说> 写在开头 我国宋代禅宗大师青原行思在<三重境界>中有这样一句话:" 参禅之初 ...

  9. Java Swing中JFreeChart构建柱状图(非3D)时关于取消柱体的高亮问题的解决纪要?

    背景 项目应用中后期的用例Demo,特此纪要! 问题 Java Swing中JFreeChart构建的柱状图(非3D)如何取消柱体的高亮显示? 说明 此Demo中点题的代码就一行,其余的代码段在其他的 ...

最新文章

  1. MySQL常见的几个错误汇总
  2. windows下faster-rcnn遇到的检测框重复很多问题 nms
  3. JAVAEE框架之SpringMVC基础
  4. 在 SAP BTP Kyma Runtime 上使用 Redis 读取和存储数据
  5. SAP CRM和Cloud for Customer里的Formatted Text控件的比较
  6. utilities(matlab)—— PSNR 值的计算
  7. sql 最外层传值给最内层查询_腾讯云高级工程师如何玩转PG查询处理与执行器算法...
  8. 绘制自己组合的k线图_史上最全K线图大全:搞懂70种K线组合形态,轻松低买高卖不踏空...
  9. 明日服务器中断,明日之后服务器连接中断 无法登陆解决办法[多图]
  10. 产品从无到有的方法框架——5MVVP框架,实际是如何运作的?
  11. OCP考试题库(精准无比)
  12. word——VBA编程
  13. pypyodbc 连接Access数据库常见报错整理
  14. 010项目沟通管理和干系人管理
  15. PRINCE2主题:商业论证,收益导向的管理艺术
  16. 为什么在Visual Studio Code 中输入的汉字变成繁体字了?电脑上其他地方的输入是正常的
  17. 整流电路 简答题与计算题
  18. 《多一点爱心》 --《年轻的潮》 汪国真
  19. k8s 中部署kafka集群
  20. 简述 RPF机制,PIM-DM工作机制,PIM-SM工作机制

热门文章

  1. 投票源码程序_[内附完整源码和文档] 基于JSP实现的影视创作论坛系统
  2. 如何创建虚拟硬盘 + os 读取硬盘参数代码
  3. jdk 版本和内部版本对应_JDK 14 Rampdown:内部版本27
  4. java开发指南_Java 12新功能完整指南
  5. selenium自动化测试_您如何使用Selenium来计算自动化测试的投资回报率?
  6. gwt-2.8.2下载_从GWT开发人员的角度概述Scala.js
  7. dynamodb分页查询_使用DynamoDBMapper查询DynamoDB项目
  8. junit5和junit4_JUnit 5 –设置
  9. maven java1.7_本周Java技巧#7 – Maven慢吗?
  10. java 观察者模式示例_观察者设计模式示例