![](/img/trans.png)
[英]Java thread updating jProgressBar does not update when thread is called again
[英]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();
不確定您到底要做什么。
上面的代碼有兩個循環:
在 makePrgressBar() 方法中,您啟動一個線程並調用 SwingUtilities.invokeLater(...) 來更新進度條,這是正確的。
但是在 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.