使用SwingWorker的Java Swing中的多线程

如果要使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369650.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序之阻止冒泡事件

众所周知&#xff0c;在微信小程序给标签绑定点击方法大家都会想到 "bindtap" 但是在页面中会遇到 点击 会冒泡而触发其他元素的时间发生 那么怎么办呢 就把引发冒泡事件的始作俑者的 bindtap 更改成catchtap 即可 转载于:https://www.cnblogs.com/wzy0526/p/8423989…

MySql Jar 包下载

MySql JAR 包下载 我们要使用Spring 链接MySql 需要两个Jar 包 一个是C3p0 一个是MySql 的Connection Jar 包 C3p0&#xff1a; 进入下面的网址 http://www.mchange.com/projects/c3p0/ 按照黄色的指示 下载 2. MySql Jar 包 进入MySql 官网 https://dev.mysql.com/down…

c语言以空格分割字符串_c语言中,输入任意字符串,任意空格隔开

c语言中,输入任意字符串,任意空格隔开关注:132 答案:3 mip版解决时间 2021-01-27 16:01提问者更无风月2021-01-27 01:51如题,希望大神代码最佳答案二级知识专家闪光的男人2021-01-27 02:50用scanf以%s读入字符串&#xff0c;即可实现输入以空格分隔的字符串。以下代码功能为&…

Unity经典游戏教程之:是男人就下100层

版权声明&#xff1a; 本文原创发布于博客园"优梦创客"的博客空间&#xff08;网址&#xff1a;http://www.cnblogs.com/raymondking123/&#xff09;以及微信公众号"优梦创客"&#xff08;微信号&#xff1a;unitymaker&#xff09;您可以自由转载&#x…

使用Flying-Saucer生成PDF中的条形码

Flying-Saucer是一个不错的库&#xff0c;可以从Java应用程序中生成PDF文档。 只需生成一堆XHTML&#xff0c;然后将其放入渲染器中&#xff0c;然后使用iText生成所需的文档即可。 但是&#xff0c;当涉及条形码时&#xff0c;Flying-Saucer无法访问iText的内置条形码功能&am…

Html和websocket初识

一、web框架 众所周知&#xff0c;对于所有的Web应用&#xff0c;本质上其实就是一个socket服务端&#xff0c;用户的浏览器其实就是一个socket客户端。 import socketdef handle_request(client):buf client.recv(1024)client.send(b"HTTP/1.1 200 OK\r\n\r\n")cli…

java lombok 视频_Java开发神器Lombok使用详解

最近正在写SpringBoot系列文章和录制视频教程&#xff0c;每次都要重复写一些Getter/Setter、构造器方法、字符串输出的ToString方法和Equals/HashCode方法等。甚是浪费时间&#xff0c;也影响代码的可读性。因此&#xff0c;今天就给大家推荐一款Java开发神器——Lombok&#…

11-[函数进阶]-闭包

1.什么是闭包&#xff1f; 内部函数对外部函数作用域里变量的引用&#xff08;非全局变量&#xff09;&#xff0c;则称内部函数为闭包。 def outer():n 10def inner():print("inner:", n)return innerval outer() print(val) val() 闭包的意义&#xff1a;返回的…

Java应该是更高级别还是更低级别?

总览 Java 8带来了许多简化的功能&#xff0c;例如Lambda表达式&#xff0c; 类型注释和虚拟扩展 。 尽管此功能很重要&#xff1a;a&#xff09;有价值&#xff0c;b&#xff09;赶上较凉的语言&#xff0c;但是这些更丰富&#xff0c;更高级的功能是Java应当重点关注的领域。…

django开发者模式中的autoreload是怎样实现的

在开发django应用的过程中&#xff0c;使用开发者模式启动服务是特别方便的一件事&#xff0c;只需要 python manage.py runserver 就可以运行服务&#xff0c;并且提供了非常人性化的autoreload机制&#xff0c;不需要手动重启程序就可以修改代码并看到反馈。刚接触的时候觉得…

html5与css3入门知识点精炼

<meta name "keywords" content"…………"/>&#xff08;网页搜索时要输入的关键字&#xff09;<meta name "author" content "作者的名字"<meta http-equiv "refresh" content "跳转的时间 ; URL跳转…

CSS实现单行、多行文本溢出显示省略号(…)

如果实现单行文本的溢出显示省略号同学们应该都知道用text-overflow:ellipsis属性来&#xff0c;当然还需要加宽度width属来兼容部分浏览。 实现方法&#xff1a; overflow: hidden; text-overflow:ellipsis; white-space: nowrap; 效果如图&#xff1a; 但是这个属性只支持单行…

java的方法是什么用,Java中的本机方法是什么?它们应该在何处使用?

A native method has the same syntax as an abstract method, but where is it implemented?解决方案What are native methods in Java and where should they be used?Once you see a small example, it becomes clear:Main.java:public class Main {public native int int…

JAXB –表示空集合和空集合

示范代码 以下演示代码将用于Java模型的所有不同版本。 它只是将一个集合设置为null&#xff0c;第二个设置为空列表&#xff0c;第三个设置为填充列表。 package package blog.xmlelementwrapper;import java.util.ArrayList; import javax.xml.bind.*;public class Demo {pu…

显示日历的指令:cal

1.显示日历的指令&#xff1a;cal &#xff08;1&#xff09;参数&#xff1a; &#xff08;2&#xff09;实例&#xff1a; 转载于:https://www.cnblogs.com/yfacesclub/p/8434449.html

简单好用的计算器:bc

1.简单好用的计算器&#xff1a;bc &#xff08;1&#xff09;参数&#xff1a; &#xff08;2&#xff09;实例&#xff1a; 执行浮点运算和一些高级函数 设定小数精度&#xff08;数值范围&#xff09; 进制转换 执行结果为&#xff1a;11000000&#xff0c;这是用bc将十进制…

Day2 第一次写python

写代码只要会Cpython就可以了Java虚拟机即可执行python代码对于Java代码 也会生成中间代码 做成虚拟机 pypy python代码 先变成字节码 再变成机器码 计算机即可识别 pypy&#xff1a;直接把代码转换成机器码 2.7 可以不加加括号3.6 一定要写括号 #&#xff01;/user/bin/python…

java注解类型命名_第三十九条:注解优先于命名模式

根据经验&#xff0c;一般使用命令模式表明有些程序元素需要通过某种工具或者框架进行特殊处理。例如&#xff0c;在Java4发行版本之前&#xff0c;JUnit测试框架原本要求用户一定要用test作为测试方法名称的开头。这种方法可行&#xff0c;但是有几个很严重的缺点。首先&#…

查看Servlet 3.0的新增功能

随着JEE6规范上市&#xff0c;在企业应用程序领域中如何开发应用程序方面发生了一些重大变化。 在本文中&#xff0c;我将介绍有关Web应用程序开发的一些更改。 首先&#xff0c;请告别web.xml部署描述符&#xff08;至少是其中的一部分&#xff09;。 好吧&#xff0c;它并不是…

block,inline,inline-block的区别

最近正在复习&#xff0c;紧张地准备几天后的笔试&#xff0c;然后刚好看到这个地方。 block&#xff1a;块级元素&#xff0c;会换行&#xff0c;如div,p,h1~h6,table这些&#xff0c;可以设置宽高&#xff1b; inline:行内元素&#xff0c;不换行&#xff0c;挤在一行显示&am…