`

swing与线程

阅读更多

swing与线程:

      1.如果一个动作需要花费很长时间,在一个独立的工作线程中坐这个事情,不要在事件分配线程中做。

                意思是可以在事件分配的线程中另起一个线程做这个事情。

      2.除了事件分配线程,不要再任何线程中接触swing组件。

 

如果一个耗时的任务,在过程中要更新GUI上的进度显示。但是由于这个耗时的工作线程不能接触GUI,如何解决?

可以使用EventQueue类的invokeLater(),和invokeAndWait()中实行。

这两个方法的区别是invokeLater()会立即返回,而invokeAndWait()会等待执行完之后返回。

e.g:下面的示范,如果接连按good按钮程序不会出现异常,但是接连按bad按钮会出现异常。

package v1ch14.SwingThreadTest;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

/**
 * This program demonstrates that a thread that runs in parallel with the event dispatch thread can
 * cause errors in Swing components.
 * @version 1.23 2007-05-17
 * @author Cay Horstmann
 */
public class SwingThreadTest
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(new Runnable()
         {
            public void run()
            {
               SwingThreadFrame frame = new SwingThreadFrame();
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               frame.setVisible(true);
            }
         });
   }
}

/**
 * This frame has two buttons to fill a combo box from a separate thread. The "Good" button uses the
 * event queue, the "Bad" button modifies the combo box directly.
 */
class SwingThreadFrame extends JFrame
{
   public SwingThreadFrame()
   {
      setTitle("SwingThreadTest");

      final JComboBox combo = new JComboBox();
      combo.insertItemAt(Integer.MAX_VALUE, 0);
      combo.setPrototypeDisplayValue("set...");
      combo.setSelectedIndex(0);

      JPanel panel = new JPanel();

      JButton goodButton = new JButton("Good");
      goodButton.addActionListener(new ActionListener()
         {
            public void actionPerformed(ActionEvent event)
            {
               new Thread(new GoodWorkerRunnable(combo)).start();
            }
         });
      panel.add(goodButton);
      JButton badButton = new JButton("Bad");
      badButton.addActionListener(new ActionListener()
         {
            public void actionPerformed(ActionEvent event)
            {
               new Thread(new BadWorkerRunnable(combo)).start();
            }
         });
      panel.add(badButton);

      panel.add(combo);
      add(panel);
      pack();
   }
}

/**
 * This runnable modifies a combo box by randomly adding and removing numbers. This can result in
 * errors because the combo box methods are not synchronized and both the worker thread and the
 * event dispatch thread access the combo box.
 */
class BadWorkerRunnable implements Runnable
{
   public BadWorkerRunnable(JComboBox aCombo)
   {
      combo = aCombo;
      generator = new Random();
   }

   public void run()
   {
      try
      {
         while (true)
         {
            int i = Math.abs(generator.nextInt());
            if (i % 2 == 0) combo.insertItemAt(i, 0);
            else if (combo.getItemCount() > 0) combo.removeItemAt(i % combo.getItemCount());
            Thread.sleep(1);
         }
      }
      catch (InterruptedException e)
      {
      }
   }

   private JComboBox combo;
   private Random generator;
}

/**
 * This runnable modifies a combo box by randomly adding and removing numbers. In order to ensure
 * that the combo box is not corrupted, the editing operations are forwarded to the event dispatch
 * thread.
 */
class GoodWorkerRunnable implements Runnable
{
   public GoodWorkerRunnable(JComboBox aCombo)
   {
      combo = aCombo;
      generator = new Random();
   }

   public void run()
   {
      try
      {
         while (true)
         {
            EventQueue.invokeLater(new Runnable()
               {
                  public void run()
                  {
                     int i = Math.abs(generator.nextInt());
                     if (i % 2 == 0) combo.insertItemAt(i, 0);
                     else if (combo.getItemCount() > 0) combo.removeItemAt(i
                           % combo.getItemCount());
                  }
               });
            Thread.sleep(1);
         }
      }
      catch (InterruptedException e)
      {
      }
   }

   private JComboBox combo;
   private Random generator;
}

 

在java6中,这样的类已经写进了类库,就是swingWorker<T,V>类,T是工作器线程的返回值,V是想过程方法传递的参数。

 e.g:

 

package v1ch14.SwingWorkerTest;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;

import javax.swing.*;

/**
 * This program demonstrates a worker thread that runs a potentially time-consuming task.
 * @version 1.1 2007-05-18
 * @author Cay Horstmann
 */
public class SwingWorkerTest
{
   public static void main(String[] args) throws Exception
   {
      EventQueue.invokeLater(new Runnable()
         {
            public void run()
            {
               JFrame frame = new SwingWorkerFrame();
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               frame.setVisible(true);
            }
         });
   }
}

/**
 * This frame has a text area to show the contents of a text file, a menu to open a file and cancel
 * the opening process, and a status line to show the file loading progress.
 */
class SwingWorkerFrame extends JFrame
{
   public SwingWorkerFrame()
   {
      chooser = new JFileChooser();
      chooser.setCurrentDirectory(new File("."));

      textArea = new JTextArea();
      add(new JScrollPane(textArea));
      setSize(DEFAULT_WIDTH, DEFAULT_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()
         {
            public void actionPerformed(ActionEvent event)
            {
               // show file chooser dialog
               int result = chooser.showOpenDialog(null);

               // if file selected, set it as icon of the label
               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()
         {
            public void actionPerformed(ActionEvent event)
            {
               textReader.cancel(true);
            }
         });
   }

   private class ProgressData
   {
      public int number;
      public String line;
   }

   private class TextReader extends SwingWorker<StringBuilder, ProgressData>
   {
      public TextReader(File file)
      {
         this.file = file;
      }

      // the following method executes in the worker thread; it doesn't touch Swing components

      @Override
      public 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); // to test cancellation; no need to do this in your programs
         }
         return text;
      }

      // the following methods execute in the event dispatch thread

      @Override
      public void process(List<ProgressData> data)
      {                                                        //事件线程也就是中间过程,这里为什么是list呢,因为publish方法的参数时可变数组,而且由publish方法传过来的数据可能不是同一个蘋率,所以当运行这个方法的时候可能publish已经运行了很多次,所以是list参数不是单个参数
         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
      public void done()
      {
         try
         {
            StringBuilder result = get();//这里得到的是doInBackground方法的返回的值,也就是工作器线程的返回值。
            textArea.setText(result.toString());     //可以操作GUI
            statusLine.setText("Done");
         }
         catch (InterruptedException ex)
         {
         }
         catch (CancellationException ex)
         {
            textArea.setText("");
            statusLine.setText("Cancelled");
         }
         catch (ExecutionException ex)
         {
            statusLine.setText("" + ex.getCause());
         }

         cancelItem.setEnabled(false);
         openItem.setEnabled(true);
      }

      private File file;
      private StringBuilder text = new StringBuilder();
   };

   private JFileChooser chooser;
   private JTextArea textArea;
   private JLabel statusLine;
   private JMenuItem openItem;
   private JMenuItem cancelItem;
   private SwingWorker<StringBuilder, ProgressData> textReader;

   public static final int DEFAULT_WIDTH = 450;
   public static final int DEFAULT_HEIGHT = 350;
}

 主要实现了上面的EventQueue类的invokeLater(),和invokeAndWait()的代替:

    doInBackground()方法来实现后台的工作线程。

    process(List<V> data) 这一方法来处理分配线程中的中间进度数据。可在这里实现对gui 的操作。

   void publish(v... data)传递中间数据到事件线程。在工作线程中可以调用它

  viod execute() 为工作器线程的执行预定这个工作器(启动工作器线程)。

 SwingWorker.StateValue  getState得到这个工作器线程的状态。

 

 

但是也有一些意外:

1。可以在任一个线程中添加或移除事件监听器

2。有些Swing方法时线程安全的

     JTextComponent.setText

     JTextArea.insert

     JTextArea.append

     JTextArea.replaceRange

     JComponent.repaint

     JComponent.revalidate

  Swing的设计者认为除了事件分配线程之外,从任何其它线程访问组件永远都是不安全的。因此你需要在事件分配线程中构建用户界面。

分享到:
评论

相关推荐

    java Swing 多线程下载器

    Java Swing多线程下载器是一种利用Java Swing库构建的图形用户界面(GUI)应用程序,它具备多线程下载功能,并支持断点续传。这样的工具类似于我们熟知的迅雷下载管理器,允许用户同时下载多个文件,提高下载速度,...

    JAVASWING多线程产生随机球

    在“JAVASWING多线程产生随机球”的项目中,开发者利用Swing创建了一个互动的应用程序,用户可以通过鼠标点击在界面上生成一个球体,这个球体会以随机的方向和速度在窗口内移动。下面将详细解释这个项目涉及的知识点...

    基于swing的多线程聊天室

    【基于Swing的多线程聊天室】是一个Java应用程序,它利用了Swing库来构建图形用户界面(GUI)并采用多线程技术实现多用户之间的实时通信。Swing是Java Standard Edition(Java SE)的一部分,提供了丰富的组件库用于...

    Swing线程的深入理解和SwingWorker基础知识介绍

    Swing线程的深入理解和SwingWorker基础知识介绍 Swing线程是Java程序设计中的一种重要概念,用于处理图形用户界面(GUI)中的线程问题。在本文中,我们将深入探讨Swing线程的理解和SwingWorker基础知识,并通过实例...

    Java雷电游戏,主要用SWING和Java的进程,纯Java代码写的,主要为开发人员对Java线程的认识

    开发者可以通过研究游戏源码了解如何创建和启动线程,以及如何使用synchronized关键字和wait/notify机制实现线程间的通信与同步,以确保游戏运行的稳定性和响应速度。 此外,Java的事件驱动模型在处理用户交互时也...

    JAVA 开发 Swing与多线程

    在Java开发中,Swing库是用来构建图形用户界面(GUI)的工具包,而多线程则是提升程序并发性能和响应能力的关键技术。Swing虽然是Java语言的一部分,但它设计为单线程模型,主要是为了简化GUI编程并避免复杂的同步...

    几个swing多线程的例子

    Java Swing 是一个用于构建桌面应用程序的用户界面工具包,它是Java Foundation Classes (JFC) 的一部分...对于初学者来说,通过研究提供的 "几个swing多线程的例子",可以更好地理解如何在实践中结合 Swing 和多线程。

    Java开发中的线程安全选择与Swing

    ### Java开发中的线程安全选择与Swing 在Java开发中,Swing作为构建桌面应用程序图形用户界面(GUI)的主要工具之一,其设计目标是为了提供一个强大、灵活且易于使用的框架。Swing允许开发者轻松创建自定义组件或...

    基于swing多线程的赛马游戏

    本项目“基于Swing多线程的赛马游戏”是一个很好的实践案例,它结合了Swing图形用户界面(GUI)和多线程技术,以模拟赛马比赛并允许用户下注和预测结果。 首先,我们要理解Swing的基础。Swing是Java的一个图形用户...

    Java Swing多线程死锁问题解析

    代码执行前判断是否处于Swing线程当中(使用SwingUtilities.isEventDispatchThread()方法),如果不是,则需要通过SwingUtilities.invokeLater(Runnable)执行,否则则直接执行代码。 在Java Swing多线程死锁问题...

    Swing线程的最后讨论 -- 利用异步模型

    【Swing线程的最后讨论 -- 利用异步模型】 Swing框架遵循单线程规则,即所有UI组件在同一时间只能被一个线程访问,通常这个线程就是事件派发线程。这一规则是为了避免多线程环境下的竞态条件和同步问题,确保组件的...

    swing,线程和网络编程教学示例

    在Java编程领域,Swing、线程和网络编程是三个重要的子领域,它们共同构建了丰富的应用程序基础。Swing主要用于创建图形用户界面(GUI),线程则是多任务处理的核心,而网络编程则允许程序通过互联网进行通信。让...

    Javaswing多线程.zip

    在Swing中,我们通常使用`javax.swing.Timer`类来实现这种定时任务,因为它与Swing事件调度线程(Event Dispatch Thread, EDT)协同工作,确保了UI更新的线程安全。 以下是一些关于Java Swing和多线程的关键知识点...

    Swing 线程之SwingUtilities invokeLater docx

    Swing 线程之 SwingUtilities invokeLater Swing 线程模型是 Java 中一个非常重要的概念,它是 Java 的图形用户界面(GUI)程序设计中的一部分。Swing 是基于 MVC 模式(Model-View-Controller)设计的,它提供了一...

    Swing线程基础经典

    Swing线程基础是Java GUI编程中的重要概念,特别是对于使用Swing库构建桌面应用程序的开发者而言。Swing设计遵循单线程模型,确保UI组件的线程安全性和响应性。以下是Swing线程基础的详细说明: 1. **Swing应用程序...

    swing界面socket多线程聊天室

    在本项目中,“swing界面socket多线程聊天室”是一个基于Java Swing的客户端-服务器通信应用,它利用TCP协议来实现实时的聊天功能。这个系统不仅提供了群聊和私聊的功能,还允许用户发送文件,并且具备用户登录与...

    Java Swing 线程 下雪效果

    在Java Swing中创建动态、交互式的应用,线程管理是一个关键的概念。当我们谈论"下雪效果"时,这意味着在Swing程序中实现一个模拟下雪场景的动画。 首先,要实现下雪效果,我们需要理解Swing的事件处理机制。Swing...

    基于java swing的多线程电梯调度模拟

    线程内部可能包含电梯的状态管理(如上行、下行、停止)、目的地处理以及与其它线程的同步机制(如wait()和notify()方法)。 接着是"ListFrame.java"。这个名字暗示着它可能是一个Swing的JFrame子类,用于构建用户...

    swing 显示时间

    在本例中,我们将探讨如何利用Swing来显示当前时间,并结合多线程的概念确保时间的实时更新。 首先,`Show.java`文件很可能包含了一个Java类,该类创建了一个Swing窗口并在其中显示时间。Swing中的`JFrame`是窗口的...

    Swing线程基础.pdf

    Swing线程基础详解 Swing作为Java的图形用户界面库,它的线程管理机制是理解和正确使用Swing的关键。Swing程序中的线程主要包括三种类型:初始化线程、UI事件调度线程(Event Dispatch Thread,简称EDT)以及任务...

Global site tag (gtag.js) - Google Analytics