【问题标题】:Calling a Background Thread in Swing在 Swing 中调用后台线程
【发布时间】:2011-11-06 22:18:28
【问题描述】:

第一个代码:

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

public class cos {
   public static int a;

   private static JLabel labeler;

   // public static Runnable r1;

   private JFrame frame;

   /**
    * Launch the application.
    */
   public static void main(String[] args) {
      a = 0;
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               cos window = new cos();
               window.frame.setVisible(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });

   }

   /**
    * Create the application.
    */
   public cos() {
      initialize();
   }

   /**
    * Initialize the contents of the frame.
    */
   public void initialize() {
      frame = new JFrame();
      frame.setBounds(100, 100, 205, 194);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      JLabel lblTime = new JLabel("Time:");
      frame.getContentPane().add(lblTime, BorderLayout.WEST);

      final JLabel labeler = new JLabel("");
      frame.getContentPane().add(labeler, BorderLayout.CENTER);

      JButton btnNewButton = new JButton("New button");
      btnNewButton.addActionListener(new ActionListener() {
         Runnable r1 = new Runnable() {
            public void run() {
               while (a <= 10) {
                  a = a + 1;
                  labeler.setText(Integer.toString(a));
                  try {
                     Thread.sleep(1000);
                  } catch (InterruptedException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                  }
               }

            }
         };

         public void actionPerformed(ActionEvent arg0) {
            Thread threder = new Thread(r1);
            threder.start();
            // liczniczek bla = new liczniczek();

         }
      });
      frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);

   }

   public void licznik() {
      while (a < 60) {
         a = a + 1;
         labeler.setText(Integer.toString(a));
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
   }
}

现在我的问题。我想使用这样的代码:

             Runnable r1 = new Runnable(){
                public void run(){
                           licznik();

                }
            };

但这不起作用。我必须做些什么来分离这段代码?对不起我的英语不好

塞兰。

【问题讨论】:

    标签: java multithreading swing


    【解决方案1】:

    不要在 EDT 期间使用 Thread#sleep(int),确定是否只有这个线程才能正常工作(使用 blockng EDT),

    Runnable r1 = new Runnable(){
       public void run(){
           licznik();
       }
    };
    

    与你调用普通 licznik(); 的相同是错误的,你必须这样包装

    Runnable r1 = new Runnable(){
       public void run(){
           labeler.setText(Integer.toString(a));    
       }
    };
    

    但同样没有Thread#sleep(int),你有三个选择

    1) 将Thread 更改为javax.swing.Timer

    2) 将Thread 更改为Runnable#Thread,您可以使用Thread#sleep(int) 进行延迟,但必须输出到GUI

    Runnable r1 = new Runnable(){
       public void run(){
           labeler.setText(Integer.toString(a));    
       }
    };
    

    3) 使用SwingWorker,其中输出在 EDT 中,您也可以使用Thread#sleep(int)

    示例Thread#sleep(int) during EDT

    put all together

    编辑

    • 不要将保留字用作类、方法、变量,以及编程语言中的任何名称(意思是cos

    • 您的代码通过实现我在此处发布的所有三个选项来工作,

    【讨论】:

    • 感谢您的想法 :) 但是:代码:wklej.to/j8OOH 和同样的错误。线程“AWT-EventQueue-0”中的异常 java.lang.NullPointerException。
    • 对不起,我不会调试任何东西,对不起,我来这里是为了我自己的享受和学习英语和摇摆舞
    • 是的 ;) 现在我有线程但是当 labeler.setText(Integer.toString(a));不是初始化函数,我有那个错误。但是谢谢你所做的一切:)
    • +1 是首选方法,但我认为invokeLater() 也可以工作,如here 所示。 (对不起,如果我看错了。)
    • 所有带有计时器的工作现在都很好。只有 labeler.setText(Integer.toString(a));给出错误。现在代码是这样的:wklej.to/eI2xs.
    【解决方案2】:

    “它不起作用”是什么意思?这个对我有用。您如何尝试使用此代码,运行它时遇到什么错误或问题?我自己,虽然我会使用 SwingWorker,但我会通过 SwingWorker 的发布/处理方法对设置 JLabel 的文本。要了解有关如何使用它的更多信息,请参阅本教程:Concurrency in Swing

    编辑
    实际上,实现您想要的更简单的方法是根本不直接使用线程或 Runnables,而是使用 Swing Timer,因为它们是为这种情况而构建的。有关更多信息,请查看Swing Timer Tutorial

    【讨论】:

    • 抱歉,我在输入答案时看不到您的更新,之前是 +1
    • @mKorbel:没关系。我们再次在大多数观点上达成一致,所以我必须 +1 你! :)
    【解决方案3】:

    我推测您希望函数 licznik() 在单独的线程中运行。您创建了一个 Runnable,但您必须做更多的事情才能使其 run() 方法执行。有几种方法可以做到这一点:

    Runnable r1 = new Runnable(){
        public void run(){
            licznik();
        }
    };
    new Thread(r1).start();
    

    或者你可以直接子类化线程:

    Thread r1 = new Thread(){
        public void run(){
            licznik();
        }
    };
    r1.start();
    

    【讨论】:

    • 仍然错误:在 cos.licznik(cos.java:86) 的线程“Thread-3”java.lang.NullPointerException 中出现异常
    • 需要continuation
    • @mKorbel - 没错。我没看到 licznik() 做了什么。
    【解决方案4】:

    Runnable 接口没有方法 licznik()。您可以使用 licznik() 方法创建实现 Runnable 的类。

    或者如果你不需要重用这个方法并且只使用一次,那么最快的方法是将它的实现移到 new Runnable() 块中

             Runnable r1 = new Runnable(){
                public void run(){
                           this.licznik();
    
                }
                public void licznik(){
                    while (a < 60){
                    a = a + 1 ;
                    labeler.setText(Integer.toString(a));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                }
            }
            }
            };
    

    【讨论】:

    • 好的。但是如果我想在初始化函数之外使用 licznik() 呢?
    【解决方案5】:

    https://github.com/greggwon/Ham 下查看 GitHub。查看https://github.com/greggwon/Ham/blob/master/SwingUtil/src/org/wonderly/swing/ComponentUpdateThread.java 中的源代码,了解我如何将整个细节打包到一个使用匿名内部类来完成工作的类中。现在可以将其更改为 lambdas,但我已经好几年没有使用 Java,因此没有进行更改。

        new ComponentUpdateThread( new Action[] { add, del, edit } ) {
            public void setup() {
                super.setup();
                list.setEnabled(false);
                list.clearSelection();
            }
            public Object construct() {
                try {
                    Vector v = remote.getData();
                    Collections.sort( v );
                    return v;
                } catch( Exception ex ) {
                    reportException(ex);
                }
                return null;
            }
            public void finished() {
                try {
                    Vector v = (Vector)getValue();
                    if( v != null ) list.setListData(v);
                } finally {
                    super.finished();
                    list.setEnabled(true);
                    edit.setEnabled(false);
                    del.setEnaled(false);
                }
            }
        }.start();
    

    通过这种工作方式,您可以使用来自周围块或其他类可见数据的最终值来控制后台线程执行之前、期间和之后发生的各个方面。

    多年来,我以各种方式更改了此代码,并且还存在其他变体。

    ComponentUpdateThread 构造函数的参数是在后台线程运行时要“禁用”的控件/操作。在后台线程中运行“构造”之前,其他启用/禁用活动可以更直接地嵌入到 setup() 和 finished() 中的活动(在 AWT 事件线程中运行)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 2012-02-19
      相关资源
      最近更新 更多