簡體   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