栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

笔记 第14章 多线程(15)Swing执行耗时任务和Swing工作器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

笔记 第14章 多线程(15)Swing执行耗时任务和Swing工作器

 

 14.11 线程与 Swing

 前言

本节内容带上了 Swing, 可能很多人看到又不想看了,但是个人建议看看,Android 系统设计本身,页面部分参考的就是这部分的思路,学习这部分,有助于Android 它的设计理念有个初步理解。

Swing 不是线程安全的,多线程操作用户页面,可能导致错误的结果,也可可能造成程序崩溃。

 14.11.1 运行耗时的任务

线程和 Swing 一起使用的两个原则:

 如果需要长时间的耗时,需要单独开启任务线程去处理,而非 Swing 所在的 UI(时间分配) 线程处理

 Swing 事件需要在特定的事件分配线程处理,不要在其他线程处理(线程不安全)

这段原则,可能看的稀里糊涂,来点简单的解释:

 更新控件的线程,不做耗时操作;

 进行耗时操作的线程,不更新控件。

❤李癩❤李癩❤李癩

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
 
public class SwingThreadTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new SwingThreadFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
 
 
}
 
class SwingThreadFrame extends JFrame{
    public SwingThreadFrame(){
        setTitle("SwingThreadTest");
 
        final JComboBox combo = new JComboBox();
        combo.insertItemAt(Integer.MAX_VALUE,0);
        combo.setPrototypeDisplayValue(combo.getItemAt(0));
        combo.setSelectedIndex(0);
 
        JPanel panel = new JPanel();
 
        JButton goodButton = new JButton("Good");
        goodButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new Thread(new GoodWorkerRunnable(combo)).start();
            }
        });
        panel.add(goodButton);
        JButton badButton = new JButton("Bad");
        badButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new Thread(new BadWorkerRunnable(combo)).start();
            }
        });
        panel.add(badButton);
 
        panel.add(combo);
        add(panel);
        pack();
 
    }
}
 
class BadWorkerRunnable implements Runnable{
    private JComboBox comboBox;
    private Random generator;
    public BadWorkerRunnable(JComboBox aCombo){
        comboBox = aCombo;
        generator = new Random();
    }
 
    @Override
    public void run() {
        try{
            while(true){
               int i = Math.abs(generator.nextInt());
               if(i % 2 == 0) comboBox.insertItemAt(i,0);
               else if(comboBox.getItemCount() > 0)
                   comboBox.removeItemAt(i%comboBox.getItemCount());
 
                Thread.sleep(1);
            }
        }catch (InterruptedException e){}
    }
}
 
class GoodWorkerRunnable implements Runnable{
    private JComboBox comboBox;
    private Random generator;
    public GoodWorkerRunnable(JComboBox aCombox){
        comboBox = aCombox;
        generator = new Random();
    }
 
    @Override
    public void run() {
        try{
            while(true){
                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        int i = Math.abs(generator.nextInt());
                        if(i % 2 == 0) comboBox.insertItemAt(i,0);
                        else if(comboBox.getItemCount() > 0)
                            comboBox.removeItemAt(i%comboBox.getItemCount());
                    }
                });
                Thread.sleep(1);
            }
        }catch (InterruptedException e){}
    }
}

❤李癩❤李癩❤李癩

执行结果:

 三个控件:好按钮、坏按钮、下拉框

 初始下拉框加入一个整型最大值

 点击好按钮效果:取一个随机数,随机到偶数插入元素;速记到奇数删除元素(有的话)

 点击坏按钮效果:和好按钮相同,但是没有单独在事件分配线程处理(while(true)耗时),可能产生线程不安全后果

好按钮:

坏按钮:

 14.11.2 使用 Swing 工作器

自定义Swing工作线程处理:TextReader extends SwingWorker();

泛型解释:返回值类型/事件分配线程参数类型

方法:doInBackGround() 第一步,工作线程处理,可进行耗时操作,不能更新页面,调用publish(data),把参数传给 process() 处理

方法:process(),doInBackGround() 第二步,调用 publish() 之后,轮到事件分配线程处理,此时通过给定的数据进行 Swing 控件更新,其中参数类型,为类种传入的第二个泛型参数的类型

方法:done() 第三步,doInBackGround() 全部处理完毕后会调用此方法,可通过get() 获取 doInBackground() 给定的返回值

另外:cancel(true) 可进行取消、中断操作

开始执行:exiecute();

如果你学过Android, 会发现里面的AsyncTask 和这个 SwingWorker 几乎一样的,非常形似。

原书作者给出的测试代码:

❤李癩❤李癩❤李癩

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
 
public class SwingWorkerTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new SwingWorkerFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}
 
class SwingWorkerFrame extends JFrame {
    private JFileChooser chooser;
    private JTextArea textArea;
    private JLabel statusLine;
    private JMenuItem openItem;
    private JMenuItem cancelItem;
    private SwingWorker textReader;
    public static final int WIDTH = 450;
    public static  final int HEIGHT = 350;
     
    public SwingWorkerFrame(){
        chooser = new JFileChooser();
        chooser.setCurrentDirectory(new File("."));
        textArea = new JTextArea();
        add(new JScrollPane(textArea));
        add(new JScrollPane(textArea));
        setSize(WIDTH,HEIGHT);
 
        statusLine = new JLabel(" ");
        add(statusLine, BorderLayout.SOUTH);
 
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);
 
        JMenu menu = new JMenu("File");
        menuBar.add(menu);
 
        openItem = new JMenuItem("Open");
        menu.add(openItem);
 
        openItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int result = chooser.showOpenDialog(null);
                if(result == JFileChooser.APPROVE_OPTION){
                    textArea.setText("");
                    openItem.setEnabled(false);
                    textReader = new TextReader(chooser.getSelectedFile());
                    textReader.execute();
                    cancelItem.setEnabled(true);
                }
            }
        });
 
        cancelItem = new JMenuItem("Cancel");
        menu.add(cancelItem);
        cancelItem.setEnabled(false);
        cancelItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textReader.cancel(true);
            }
        });
 
    }
     
    public class ProgressData{
        public int number;
        private String line;
    }
    private class TextReader extends SwingWorker{
        private File file;
        private StringBuilder text = new StringBuilder();
        public TextReader(File file){
            this.file = file;
        }
 
        @Override
        protected StringBuilder doInBackground() throws IOException,InterruptedException {
            int lineNumber = 0;
            Scanner in = new Scanner(new FileInputStream(file));
            while(in.hasNextLine()){
                String line = in.nextLine();
                lineNumber++;
                text.append(line);
                text.append("n");
                ProgressData data = new ProgressData();
                data.number = lineNumber;
                data.line = line;
                publish(data);
                Thread.sleep(1);
            }
            return text;
        }
 
        @Override
        protected void process(List data) {
            if(isCancelled()) return;
            StringBuilder b = new StringBuilder();
            statusLine.setText(""+data.get(data.size()-1).number);
            for(ProgressData d:data){
                b.append(d.line);
                b.append("n");
            }
            textArea.append(b.toString());
        }
 
        @Override
        protected void done() {
            try{
                StringBuilder result = get();
                textArea.setText(result.toString());
                statusLine.setText("Done");
            }catch (InterruptedException e){
                 
            }catch (CancellationException ex){
                textArea.setText("");
                statusLine.setText("Canceled");
            }catch (ExecutionException ex){
                statusLine.setText(""+ex.getCause());
            }
            cancelItem.setEnabled(false);
            openItem.setEnabled(true);
        }
    }
}

❤李癩❤李癩❤李癩

执行结果:

 左上角菜单可选择读入文件

 左下角读入文件显示行数,文本域会显示读入内容

 读取完毕后会显示Done

 如果在读取中选择了Cancel,则内容会情况,左下角显示Cancel

 相关内容:选择 《Java核心技术 卷1》查找相关笔记

评论点赞收藏✨关注,是送给作者最好的礼物,愿我们共同学习,一起进步

如果对作者发布的内容感兴趣,可点击下方关注公众号 钰娘娘知识汇总 查看更多作者文章哦!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/863516.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号