繁体   English   中英

JProgressBar 更新和线程调度

[英]JProgressBar update and thread scheduling

你好堆栈交换器,

java Swing 中的进度条有问题。 我认为我的困惑源于我对线程和 Swing 事件队列的理解不足(我不太了解 java 线程,以及AWTEventQueue上发生的事情,尽管我通常了解多线程是关于什么的)。

上下文是按下JButton以开始长时间计算。 在计算开始之前,我在JFrame制作了一个进度条,我认为它会被绘制,但事实并非如此。 框架出现,但它只是灰色。 在本例中,按钮上写有“clickMe”。

在“clickMe”动作侦听器中,我首先在“运行”的子任务中创建并显示一个JFrame (我不清楚何时安排 TBH)。 然后,我调用doTask() ,它与动作侦听器在同一线程中运行(我认为是AWTEventThread ??)。 doTask()运行,将数字打印到控制台。 doTask()输出混合的是进度条的迭代计数(从动作侦听器启动makeProgressBar()开始)。

因此,从输出看来,进度条和AWTEventThread都在运行,但JProgressBar GUI 中设置的值从未更新。

如何更改我的代码以便更新 GUI? 我尝试理解JProgressBar教程并在网上搜索,但我认为我的问题更多是对 Java 任务的概念性理解。

这是我的代码:

package problemclass;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

public class ProblemClass 
{

    void progressBarButtonClick()
    {
        JFrame buttonInAFrame = new JFrame();
        JPanel buttonInAFramePanel = new JPanel();
        JButton clickMe = new JButton("Click me!");

        buttonInAFramePanel.add(clickMe);       


        clickMe.addActionListener(new ActionListener() {
            @Override
                    public void actionPerformed(ActionEvent e) 
                {
                JFrame progBarFrame = makeProgressBar();                
                doTask();
                progBarFrame.dispose();
                    }
        });


        buttonInAFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        buttonInAFrame.add(buttonInAFramePanel);
        buttonInAFrame.pack();
        buttonInAFrame.setVisible(true);
    }

    private void doTask()
    {

        for(int i = 0; i < 20000; i++)
        {
            if (i % 100 == 0) 
            {
                System.out.println("TASK iteration " + i);

                try 
                {
                    Thread.sleep(1000);
                } 
                catch (InterruptedException e) {}
            }
        }
    }

    private JFrame makeProgressBar()
    {
        JFrame progBarFrame = new JFrame();
        JPanel progBarPanel = new JPanel();

        JProgressBar progressBar = new JProgressBar();
        progBarPanel.add(progressBar);      
        progressBar.setValue(0);
            progressBar.setStringPainted(true);
            progressBar.setIndeterminate(true);


        new Thread(new Runnable() 
        {
            public void run() 
            {
                for (int i = 0; i <= 100; i++) 
                {

                    final int j = i; 
                    System.out.println("Progress Iteration " + j);

                    SwingUtilities.invokeLater(new Runnable() 
                    {
                        public void run() 
                        {
                           progressBar.setValue(j);
                        }
                    });

                    try 
                    {
                        java.lang.Thread.sleep(100);
                    }
                    catch(Exception e) { }
                }
            }
        }).start();

        progBarFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        progBarFrame.add(progBarPanel);
        progBarFrame.pack();
        progBarFrame.setVisible(true);

        return progBarFrame;
    }
    public static void main(String[] args)
    {
        EventQueue.invokeLater(() ->
        {       
            new ProblemClass().progressBarButtonClick();
        });
    }
}
JFrame progBarFrame = makeProgressBar();                
doTask();

不确定您到底要做什么。

上面的代码有两个循环:

  1. 在 makePrgressBar() 方法中,您启动一​​个线程并调用 SwingUtilities.invokeLater(...) 来更新进度条,这是正确的。

  2. 但是在 doTack() 中你开始另一个循环。 这次您没有启动线程,因此在 EDT 上调用代码,并且由于您使用 Thread.sleep,EDT 将休眠并且 GUI 不会重新绘制自身,直到整个循环完成。

我建议你去掉 doTask() 方法,因为我不知道为什么你需要两个循环的代码块。 或者如果你真的需要它,那么你还需要使用一个线程和 invokeLater(...)。

就像你一样,我最近做了一些关于进度条和线程的工作,直到我意识到它是如此简单。简而言之,这是我点击按钮时的代码:

 // Create 2 threads. One handles your GUI. Other does the task
        Thread t1 = new Thread(new Runnable() {
          @Override
          public void run() {
          // code goes here.
          //In here I choose to hide the button, display the progress bar
                      }
          });  
        t1.start();

       Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            // code goes here.
            //In here I get the task done, then hide the progress bar

             }
           });  
        t2.start();

每次都像魅力一样。 希望能帮助到你!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM