java 我的 JProgressBar 直到 100% 才更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10437590/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
My JProgressBar is not Updating Until it is 100%
提问by Patrick Aquilone
Ok, I have the following code.
好的,我有以下代码。
public class MyProgressBar extends JPanel implements MyData, Serializable {
/**
*
*/
public static final int MAX = 10000;
public static final int WIDTH = 400;
public static final int HEIGHT = 75;
private JProgressBar MyBar = new JProgressBar( SwingConstants.HORIZONTAL, 0, MAX );
private JFrame MyFrame = new JFrame();
private int MyValue = 0;
private Thread MyThread = new Thread( new ProgressThread() );
public MyProgressBar() {
add(MyBar);
int x = ( MyData.SCREEN.width / 2 ) - ( WIDTH / 2);
int y = ( MyData.SCREEN.height / 2 ) - ( HEIGHT / 2);
this.setBounds( x, y, WIDTH, HEIGHT );
MyFrame.setBounds( x, y, WIDTH, HEIGHT );
MyFrame.setUndecorated(true);
MyFrame.getContentPane().setSize( new Dimension( WIDTH, HEIGHT ) );
MyFrame.setMinimumSize( new Dimension( WIDTH, HEIGHT ) );
MyFrame.setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
MyFrame.setSize( new Dimension( WIDTH, HEIGHT ) );
MyFrame.setVisible(false);
MyFrame.getContentPane().setLayout(null);
MyBar.setStringPainted( true );
MyBar.setBorderPainted( true );
MyBar.setValue( 0 );
MyBar.setBounds( 0, 0, WIDTH, HEIGHT );
MyFrame.add( MyBar );
MyFrame.pack();
MyFrame.repaint();
}
public void MyUpdateBar() {
MyBar.setValue( MyValue );
MyBar.repaint();
MyFrame.repaint();
this.repaint();
//dbug.Message( "MYPROGRESSBAR", "MyUpdateBar", "Value is %3.2f %d", MyBar.getPercentComplete(), MyValue );
}
public void MySetValue( int percent ) {
MyValue = (int)( MAX * ( (double)percent / 100.0 ) );
MyUpdateBar();
//dbug.Message( "MYPROGRESSBAR", "MySetValue", "Value is %3.2f %d percent was %d", MyBar.getPercentComplete(), MyValue, percent );
}
public void CreateAndShow () {
MyFrame.setVisible(true);
MyThread.start();
}
public void HideAndClear () {
MyThread.stop();
//frame.setVisible(false);
}
class ProgressThread implements Runnable {
public void run() {
EventQueue.invokeLater(new Runnable() {
public void run() {
while( MyValue < MyBar.getMaximum() ) {
MyBar.setValue( MyValue );
MyBar.repaint();
MyFrame.repaint();
dbug.Message( "MYPROGRESSBAR", "THREAD", "Value is %3.2f %d", MyBar.getPercentComplete(), MyValue );
}
}
});
}
}
}
As you can see, I have created a class that I want to have show the progress. What happens is I instantiate the class. Load my XML file, then as I am parsing data, I am calling to update the MyValue which I see when I let my dbug messages come out. However, the bar itself does not even show until it is 100% complete. I have read about threading and following someone else's example and if I left it as his example it worked. If I made a few tweaks (changing a loop in the thread to populate the setvalue of the progress bar to read a value) it does not even show until it is 100.
如您所见,我创建了一个类来显示进度。发生的事情是我实例化了这个类。加载我的 XML 文件,然后当我解析数据时,我正在调用更新 MyValue,当我让我的 dbug 消息出来时,我会看到它。但是,在 100% 完成之前,条形图本身甚至不会显示。我已经阅读了有关线程和遵循其他人的示例的内容,如果我将其作为他的示例,它会起作用。如果我进行了一些调整(更改线程中的循环以填充进度条的设置值以读取值),它甚至不会显示到 100。
What did I do wrong?
我做错了什么?
Thanks!
谢谢!
回答by tenorsax
You thread executes SwingUtilities.invokeLater
. You're effectively running on Swing's Event Dispatch Thread
. Not sure what are you trying to achieve. But it looks like you are blocking EDT
and your while
loop is not updated as MySetValue
is not executed.
你线程执行SwingUtilities.invokeLater
。您正在有效地运行 Swing 的Event Dispatch Thread
. 不知道你想达到什么目的。但看起来您正在阻塞EDT
并且您的while
循环未更新,因为MySetValue
未执行。
Consider using SwingWorker
for lengthy operations. How to Use Progress Barsdemonstrates use of SwingWorker
with JProgressBar
.
考虑SwingWorker
用于冗长的操作。如何使用进度条演示了SwingWorker
with 的使用JProgressBar
。
Make sure you call setValue
method from the Event Dispatch Thread
. You can use SwingUtilities.invokeLater
for that. Read more about Threads and Swing.
确保您setValue
从Event Dispatch Thread
. 你可以用SwingUtilities.invokeLater
它。阅读有关线程和 Swing 的更多信息。
Consider this simplified sample:
考虑这个简化的示例:
public static void main(String[] arguments) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
final JProgressBar bar = new JProgressBar(0, 100);
Thread t = new Thread(){
public void run(){
for(int i = 0 ; i < 100 ; i++){
final int percent = i;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
bar.setValue(percent);
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
}
};
frame.add(bar);
frame.pack();
frame.setVisible(true);
t.start();
}
回答by Guillaume Polet
The problem is that you use a loop in the EDT that updates the progress. Until that loop exits, the EDT cannot dispatch events (like repaint, revalidate, invokeLater, mouse events, key events, etc...) preventing it from refreshing the progress bar.
问题是您在 EDT 中使用了一个循环来更新进度。在该循环退出之前,EDT 无法调度事件(如重绘、重新验证、invokeLater、鼠标事件、键事件等),阻止它刷新进度条。
You should try to find a way to let the EDT dispatch its events between each update of the progress bar. Ideally, you move your "work" outside the EDT with a SwingWorker, and meanwhile the progressbar get updated through property change listeners in the EDT.
您应该尝试找到一种方法,让 EDT 在进度条的每次更新之间调度其事件。理想情况下,您使用SwingWorker将“工作”移到 EDT 之外,同时进度条通过 EDT 中的属性更改侦听器进行更新。
For your information, in Java, methods and variables starts with a lower case letter. Your code is really hard to read for others.
仅供参考,在 Java 中,方法和变量以小写字母开头。您的代码对其他人来说真的很难阅读。
回答by Patrick Aquilone
So, I tried to follow the tutorial and here is where I am at.
因此,我尝试按照教程进行操作,这就是我所处的位置。
Ok, I have tried following tutorials but I keep getting lost somewhere. What I need is a class that creates and displays a progress bar (JProgressBar) that I can set the value of as I iterate over data loaded from a file and place into the database memory. My problems come that every example I have found has some kind of counter that fills the progress bar and executes from a "main" function. Every time I alter that tutorial to be a class that I can call at will and display the bar, I do not get the bar showing (ie the frame comes up but the bar does not even look like it is added to the frame until after the iteration is done). I have tried using SwingUtilities.invokeLater and SwingWorker (lastest attempt at class below) all having the same issue. To make matters worse, I can do a dbug.myMessage (basically sends to System.out) and see a message that shows that the bar is changing in memory just not showing. I am obviously missing something probably simple but I can't think of what it is.
好的,我已经尝试过遵循教程,但我一直在某个地方迷路。我需要的是一个创建和显示进度条 (JProgressBar) 的类,我可以在迭代从文件加载的数据并将其放入数据库内存时设置它的值。我的问题是,我发现的每个示例都有某种计数器,可以填充进度条并从“主”函数执行。每次我将该教程更改为可以随意调用并显示栏的课程时,我都没有显示栏(即框架出现但栏甚至看起来都没有添加到框架中,直到之后迭代完成)。我曾尝试使用 SwingUtilities.invokeLater 和 SwingWorker(在下面的课堂上的最新尝试)都有同样的问题。更糟糕的是,我可以做一个 dbug.myMessage(基本上发送到 System.myMessage)。out) 并看到一条消息,表明该条在内存中正在发生变化,只是没有显示。我显然错过了一些可能很简单的东西,但我想不出它是什么。
Oh, one other thing, if I leave the tutorial as is (http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ProgressBarDemo2Project/src/components/ProgressBarDemo2.java) and just change the main to a createAndShow method, it works but of course it does not do what I need it to do.
哦,另一件事,如果我将教程保留原样(http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/ examples/components/ProgressBarDemo2Project/src/components/ProgressBarDemo2.java) 并将 main 更改为 createAndShow 方法,它可以工作,但当然它没有做我需要它做的事情。
I did post another question about this but have altered the class so much I thought it best to post a new question.
我确实发布了关于此的另一个问题,但已经改变了课程,我认为最好发布一个新问题。
So, here is my altered code that does not seem to work:
所以,这是我修改过的代码,但似乎不起作用:
public class MyProgressBar extends JPanel implements PropertyChangeListener,
MyData,
Serializable {
/**
*
*/
private static final long serialVersionUID = -1632492668549544408L;
private MyDebug dbug = new MyDebug( MyData.MYDEBUGCHECK.MYPROGRESSBAR.getOn() );
public static final int MAX = 100;
public static final int WIDTH = 400;
public static final int HEIGHT = 75;
private JProgressBar myBar = new JProgressBar( SwingConstants.HORIZONTAL, 0, MAX );
private JFrame myFrame = new JFrame();
public Task task;
class Task extends SwingWorker<Void, Void> {
public int myValue = 0;
@Override
public Void doInBackground() {
//Initialize progress property.
setProgress(0);
while (myValue < 100) {
//Make random progress.
//myValue += random.nextInt(10);
setProgress( Math.min( myValue, 100 ) );
dbug.myMessage( "MYPROGRESSBAR", "doInBackground", "Value is %3.2f %d", myBar.getPercentComplete(), myValue );
myBar.repaint();
}
return null;
}
public void done() {
}
public void mySetValue( int percent ) {
myValue = (int)( MAX * ( (double)percent / 100.0 ) );
dbug.myMessage( "MYPROGRESSBAR", "mySetValue", "Value is %3.2f %d percent was %d", myBar.getPercentComplete(), myValue, percent );
}
}
public MyProgressBar() {
add(myBar);
int x = ( MyData.SCREEN.width / 2 ) - ( WIDTH / 2);
int y = ( MyData.SCREEN.height / 2 ) - ( HEIGHT / 2);
this.setBounds( x, y, WIDTH, HEIGHT );
myFrame.setBounds( x, y, WIDTH, HEIGHT );
myFrame.setUndecorated(true);
myFrame.getContentPane().setSize( new Dimension( WIDTH, HEIGHT ) );
myFrame.setMinimumSize( new Dimension( WIDTH, HEIGHT ) );
myFrame.setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
myFrame.setSize( new Dimension( WIDTH, HEIGHT ) );
myFrame.setVisible(false);
myFrame.getContentPane().setLayout(null);
myFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
myBar.setStringPainted( true );
myBar.setBorderPainted( true );
myBar.setValue( 0 );
myBar.setBounds( 0, 0, WIDTH, HEIGHT );
myBar.addPropertyChangeListener( this );
myFrame.add( myBar );
//Create and set up the content pane.
//JComponent newContentPane = new MyProgressBar();
JComponent newContentPane = myBar;
newContentPane.setOpaque(true); //content panes must be opaque
myFrame.setContentPane(newContentPane);
myFrame.pack();
}
public void createAndShow () {
//Display the window.
myFrame.setVisible(true);
myFrame.repaint();
}
public void hideAndClear () {
//myFrame.setVisible(false);
}
@Override
public void propertyChange(PropertyChangeEvent args) {
dbug.myMessage( "MYPROGRESSBAR", "propertyChange", "Value is %s", args.getPropertyName() );
if ( "progress" == args.getPropertyName() ) {
int progress = (Integer) args.getNewValue();
//myBar.setValue(progress);
}
}
public void start () {
//Instances of javax.swing.SwingWorker are not reusuable, so
//we create new instances as needed.
task = new Task();
task.addPropertyChangeListener(this);
task.execute();
}
}
回答by Kirk Patrick Brown
The below snippet updates the progress bar while in progress
以下代码段在进行时更新进度条
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressBar.setValue((int)percentage);
//below code to update progress bar while running on thread
progressBar.update(progressBar.getGraphics());}
});