java 在一个线程中的 JDialog 中显示一个不确定的进度条并同时在另一个线程中运行一个任务
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12105182/
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
Show an indeterimante progress bar in a JDialog in a thread and run a task in another thread concurrently
提问by Alptugay
When a user clicks a button, a long task of approximately 10 seconds will run. During this time I want to show a progress bar to the user. But the main thread has to wait for the worker thread to finish because the worker thread will set a variable that the main thread will use. If I don't wait the worker thread I will get a NullPointerException
when using the variable. So after the worker thread finishes, I will also close the progress bar dialog.
当用户单击按钮时,将运行大约 10 秒的长任务。在此期间,我想向用户显示进度条。但是主线程必须等待工作线程完成,因为工作线程将设置一个主线程将使用的变量。如果我不等待工作线程,我会NullPointerException
在使用变量时得到一个。所以在工作线程结束后,我也会关闭进度条对话框。
When I wait for the worker thread using join()
the progress bar dialog shows (interestingly without the progress bar though) and hangs there.
当我使用join()
进度条对话框等待工作线程时(有趣的是没有进度条)并挂在那里。
Thread runnable = new Thread() {
public void run() {
try {
System.out.println("thread basladi");
threadAddSlaveReturnMessage = request.addSlave(
ipField.getText(), passField.getText(),
nicknameField.getText());
System.out.println("thread bitti");
} catch (LMCTagNotFoundException e) {
e.printStackTrace();
}
}
};
Thread runnable_progress = new Thread() {
public void run() {
JTextArea msgLabel;
JDialog dialog;
JProgressBar progressBar;
final int MAXIMUM = 100;
JPanel panel;
progressBar = new JProgressBar(0, MAXIMUM);
progressBar.setIndeterminate(true);
msgLabel = new JTextArea("deneme");
msgLabel.setEditable(false);
panel = new JPanel(new BorderLayout(5, 5));
panel.add(msgLabel, BorderLayout.PAGE_START);
panel.add(progressBar, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11));
dialog = new JDialog(Frame.getFrames()[0], "baslik", true);
dialog.getContentPane().add(panel);
dialog.setResizable(false);
dialog.pack();
dialog.setSize(500, dialog.getHeight());
dialog.setLocationRelativeTo(null);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setAlwaysOnTop(false);
dialog.setVisible(true);
msgLabel.setBackground(panel.getBackground());
}
};
runnable.start();
System.out.println("runnable start");
runnable_progress.start();
System.out.println("progress start");
runnable.join();
System.out.println("runnable join");
runnable_progress.join();
System.out.println("progress join");
if (threadAddSlaveReturnMessage.equalsIgnoreCase("OK")) {
fillInventoryTable(inventoryTable);
JOptionPane.showMessageDialog(this, messages.getString("centrum.addslavepanel.SUCCESS"), null, JOptionPane.INFORMATION_MESSAGE);
}
"progress join"
“进步加入”
doesn't get printed.
不会打印。
采纳答案by mKorbel
you have the issue with Concurency is Swing, your GUI is visible after all thread are done
is possible to moving with JProgressBar(I'm talking about you code) but you have to
create and show JDialog, create once time and reuse this container
then to start
Thread
,better could be from
Runnable#Thread
output to the Swing GUI must be wrapped into
invokeLater()
this is exactly job for using SwingWorkerand with PropertyChangeListener
您遇到的问题是Concurency is Swing,在所有线程完成后您的 GUI 可见
可以使用JProgressBar移动(我说的是你的代码),但你必须
回答by uahakan
You can use a SwingWorkerhere. A short example :
您可以在此处使用SwingWorker。一个简短的例子:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.godel.nio;
import java.awt.BorderLayout;
import java.util.List;
import javax.swing.*;
/**
*
* @author internet_2
*/
public class Test {
public static void main(String[] args) {
new Test().doJob();
}
public void doJob() {
JTextArea msgLabel;
JProgressBar progressBar;
final int MAXIMUM = 100;
JPanel panel;
progressBar = new JProgressBar(0, MAXIMUM);
progressBar.setIndeterminate(true);
msgLabel = new JTextArea("deneme");
msgLabel.setEditable(false);
panel = new JPanel(new BorderLayout(5, 5));
panel.add(msgLabel, BorderLayout.PAGE_START);
panel.add(progressBar, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11));
final JDialog dialog = new JDialog();
dialog.getContentPane().add(panel);
dialog.setResizable(false);
dialog.pack();
dialog.setSize(500, dialog.getHeight());
dialog.setLocationRelativeTo(null);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setAlwaysOnTop(false);
dialog.setVisible(true);
msgLabel.setBackground(panel.getBackground());
SwingWorker worker = new SwingWorker() {
@Override
protected void done() {
// Close the dialog
dialog.dispose();
}
@Override
protected void process(List chunks) {
// Here you can process the result of "doInBackGround()"
// Set a variable in the dialog or etc.
}
@Override
protected Object doInBackground() throws Exception {
// Do the long running task here
// Call "publish()" to pass the data to "process()"
// return something meaningful
return null;
}
};
worker.execute();
}
}
Edit : "publish()" should be called in "doInBackground()" to pass the data to "process()".
编辑:“发布()”应该被称为“doInBackground()”将数据传递到“流程()”。
回答by Sebastian_H
As the previous answers already mentioned, SwingWorker
is the way to go, if use want to use concurrency with Swing.
I found this SwingWorker and ProgressBar tutorialquite useful in understanding how it all works together.
Coming back to your actual problem: I assume you use a GUI, because you stated the user has to click a button. The question is, what is your "main thread" doing? Does it really have to run all the time? Doesn't look like it. Because you said the thread needs a variable which is set by another thread, which is a result of a user interaction. In short: Why does it need to run if it's dependent on a user interaction anyway?
The usual way would be to first get all the data you need and then run the calculations or whatever. In your case, either run everything in a single background thread(set the variable first then do the rest), started by the ActionListener of your button or run the other thread afterthe thread where you set the variable has completed.
You could for example use the method done()
, provided by SwingWorker
, to launch the next task. Or if you really have to, you could wait in a loop for task.isDone()
to return true. But don't forget to check for isCancelled()
too.
Anyway, I think you should rethink your design. Because what I can see from the limited information provided looks overly complicated to me.
正如前面的答案已经提到SwingWorker
的那样,如果使用要使用 Swing 的并发性,这是要走的路。
我发现这个SwingWorker 和 ProgressBar 教程对于理解它们如何协同工作非常有用。
回到您的实际问题:我假设您使用 GUI,因为您声明用户必须单击一个按钮。问题是,你的“主线程”在做什么?它真的必须一直运行吗?看起来不像 因为你说线程需要一个由另一个线程设置的变量,这是用户交互的结果。简而言之:如果它依赖于用户交互,为什么还需要运行?
通常的方法是首先获取您需要的所有数据,然后运行计算或其他任何方式。在您的情况下,要么在单个后台线程中运行所有内容(先设置变量,然后执行其余操作),由按钮的 ActionListener 启动,要么在设置变量的线程完成后运行另一个线程。
例如,您可以使用由done()
提供的方法SwingWorker
来启动下一个任务。或者,如果您真的必须这样做,您可以在循环中等待task.isDone()
返回true。但也不要忘记检查isCancelled()
。
无论如何,我认为您应该重新考虑您的设计。因为我从所提供的有限信息中看到的东西对我来说似乎过于复杂。