![](/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.