简体   繁体   English

JProgressBar 更新和线程调度

[英]JProgressBar update and thread scheduling

Hello stack exchangers,你好堆栈交换器,

I have a problem with progress bars in java Swing. java Swing 中的进度条有问题。 I think my confusions arise from my poor understanding of threads and the Swing event queue (I don't know much about java Threads, and exactly what is happening on the AWTEventQueue , although I generally understand what multithreading is about).我认为我的困惑源于我对线程和 Swing 事件队列的理解不足(我不太了解 java 线程,以及AWTEventQueue上发生的事情,尽管我通常了解多线程是关于什么的)。

The context is that a JButton is pressed to start a long calculation.上下文是按下JButton以开始长时间计算。 Before the calculation starts, I make a progress bar in a JFrame , which I thought would be painted, but it isn't.在计算开始之前,我在JFrame制作了一个进度条,我认为它会被绘制,但事实并非如此。 The frame appears, but it is just grey.框架出现,但它只是灰色。 The button, in this example has "clickMe" written on it.在本例中,按钮上写有“clickMe”。

In the "clickMe" action listener, I first make and display a JFrame in a subtask which is "run" (I'm not clear on when this is scheduled TBH).在“clickMe”动作侦听器中,我首先在“运行”的子任务中创建并显示一个JFrame (我不清楚何时安排 TBH)。 Then, I call doTask() which is running in the same thread as the action listener (which I think is the AWTEventThread ??).然后,我调用doTask() ,它与动作侦听器在同一线程中运行(我认为是AWTEventThread ??)。 The doTask() runs, printing out numbers to the Console. doTask()运行,将数字打印到控制台。 Intermixed with the doTask() output are iteration counts of the progressbar (from when the action listener started makeProgressBar() ).doTask()输出混合的是进度条的迭代计数(从动作侦听器启动makeProgressBar()开始)。

So, from the output, it looks like both the progress bar is running and the AWTEventThread , but the value set in the JProgressBar GUI is never updated.因此,从输出看来,进度条和AWTEventThread都在运行,但JProgressBar GUI 中设置的值从未更新。

How can I change my code so that the GUI gets updated?如何更改我的代码以便更新 GUI? I've tried understanding the JProgressBar tutorial and hunted around the web, but I think my problem is more a conceptual understanding of Java Tasks.我尝试理解JProgressBar教程并在网上搜索,但我认为我的问题更多是对 Java 任务的概念性理解。

This is my code:这是我的代码:

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();

Not sure exactly what you are trying to do.不确定您到底要做什么。

The above code has two loops:上面的代码有两个循环:

  1. In the makePrgressBar() method you start a Thread and invoke SwingUtilities.invokeLater(…), to update the progress bar, which is correct.在 makePrgressBar() 方法中,您启动一​​个线程并调用 SwingUtilities.invokeLater(...) 来更新进度条,这是正确的。

  2. but then in doTack() you start another loop.但是在 doTack() 中你开始另一个循环。 This time you don't start a Thread so the code is invoked on the EDT and since you use Thread.sleep, the EDT will sleep and the GUI will not repaint itself until the entire loop is finished.这次您没有启动线程,因此在 EDT 上调用代码,并且由于您使用 Thread.sleep,EDT 将休眠并且 GUI 不会重新绘制自身,直到整个循环完成。

I would suggest you get rid of the doTask() method since I don't know why you need two blocks of code that loop.我建议你去掉 doTask() 方法,因为我不知道为什么你需要两个循环的代码块。 Or if you really need it, then you also need to use a Thread and invokeLater(…).或者如果你真的需要它,那么你还需要使用一个线程和 invokeLater(...)。

Just like you, I recently did some work on progress bars and threading and went nuts until I realized that it is just so simple.In a nutshell this is the code I have when my button is clicked:就像你一样,我最近做了一些关于进度条和线程的工作,直到我意识到它是如此简单。简而言之,这是我点击按钮时的代码:

 // 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();

Works like a charm every time.每次都像魅力一样。 Hope it helps!希望能帮助到你!

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

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