2 回答
TA貢獻1821條經驗 獲得超6個贊
一個巨大的問題就在這里:
protected void done() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pDialog.dispose();
}
在 EDT 或事件調度線程上調用worker 的done()方法,并且您知道當您休眠該線程時會發生什么——整個 GUI 進入休眠狀態并變得完全沒有響應。如果您想延遲對話框的處理并保持您的 GUI 正常運行,請不要這樣做,實際上永遠不要調用Thread.sleepEDT。
選項1:
相反,在大多數其他 Swing 延遲策略中,使用 Swing Timer,例如,類似這樣的東西(代碼未測試):
protected void done() {
int timerDelay = 5000;
new Timer(timerDelay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
pDialog.dispose();
((Timer) e.getSource).stop();
}
}).start();
}
如果您不熟悉 Swing Timer 的使用,請查看Swing Timer 教程
選項 2:
把你放在Thread.sleep(5000)你方法的最后doInBackground(),就在之前return null;
另一個問題:您正在使用發布/處理方法對,但只使用了一次,這違背了它的目的。也許您打算在輪詢 while 循環中調用發布?當然你只能調用get()一次,但是有沒有另一種方法可以從你正在調用的正在運行的進程中提取信息?如果是這樣,則需要間歇性地獲取信息,無論是在輪詢 while 循環中,還是通過任何允許您提取臨時結果的過程。
例如:
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import javax.swing.*;
public class TestProgressDialog extends JPanel {
private static final long serialVersionUID = 1L;
private ProgressDialog pDialog;
private JSpinner taskNumberSpinner = new JSpinner(new SpinnerNumberModel(10, 1, 20, 1));
public TestProgressDialog() {
setPreferredSize(new Dimension(800, 650));
add(new JButton(new AbstractAction("Launch Dialog") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
Window owner = SwingUtilities.windowForComponent(TestProgressDialog.this);
String title = "Dialog";
ModalityType modal = ModalityType.MODELESS;
int numTasks = (int) taskNumberSpinner.getValue();
pDialog = new ProgressDialog(owner, title, modal, numTasks);
pDialog.pack();
pDialog.setLocationByPlatform(true);
pDialog.append("Initializing background tasks\n");
MyWorker myWorker = new MyWorker(numTasks, pDialog);
myWorker.addPropertyChangeListener(new WorkerListener(pDialog));
myWorker.execute();
pDialog.setVisible(true);
}
}));
add(new JLabel("Number of Tasks:"));
add(taskNumberSpinner);
}
private static void createAndShowGui() {
TestProgressDialog mainPanel = new TestProgressDialog();
JFrame frame = new JFrame("Test Progress Dialog");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
interface Progressable {
void setProgress(int progress);
void append(String text);
}
class ProgressDialog extends JDialog implements Progressable {
private static final long serialVersionUID = 1L;
private JProgressBar progressBar = new JProgressBar(0, 100);
private JTextArea textArea = new JTextArea(10, 30);
private JScrollPane scrollPane = new JScrollPane(textArea);
ProgressDialog(Window owner, String title, ModalityType modal, int nunTasks) {
super(owner, title, modal);
progressBar.setStringPainted(true);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(progressBar, BorderLayout.PAGE_START);
add(scrollPane);
}
@Override
public void append(String text) {
textArea.append(text);
}
@Override
public void setProgress(int progress) {
progressBar.setValue(progress);
}
}
class MyCallable implements Callable<String> {
private static final long MAX_DUR = 6 * 1000;
private static final long MIN_DUR = 1000;
private String text;
public MyCallable(String text) {
this.text = text;
}
public String getText() {
return text;
}
@Override
public String call() throws Exception {
// just wait some random delay and then return a String
long timeout = (long) (Math.random() * MAX_DUR + MIN_DUR);
TimeUnit.MILLISECONDS.sleep(timeout);
return text + " time out: " + timeout;
}
}
class WorkerListener implements PropertyChangeListener {
private Progressable progressable;
public WorkerListener(Progressable progressable) {
this.progressable = progressable;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName() != null && evt.getPropertyName().equals("progress")) {
int progress = (int)evt.getNewValue();
progressable.setProgress(progress);
}
}
}
class MyWorker extends SwingWorker<Void, String> {
private Progressable progressable;
private List<Future<String>> futures = new ArrayList<>();
private CompletionService<String> completionService;
private int numTasks;
// private BlockingQueue<Future<String>> completionQueue;
public MyWorker(int numTasks, Progressable progressable) {
this.numTasks = numTasks;
this.progressable = progressable;
ExecutorService service = Executors.newFixedThreadPool(numTasks);
completionService = new ExecutorCompletionService<>(service);
for (int i = 0; i < numTasks; i++) {
futures.add(completionService.submit(new MyCallable("My Callable " + i)));
}
service.shutdown();
}
@Override
protected Void doInBackground() throws Exception {
while (futures.size() > 0) {
Future<String> future = completionService.take();
futures.remove(future);
int progress = (100 * (numTasks - futures.size())) / numTasks;
progress = Math.min(100, progress);
progress = Math.max(0, progress);
setProgress(progress);
if (future != null) {
publish(future.get());
}
}
return null;
}
@Override
protected void process(List<String> chunks) {
for (String chunk : chunks) {
progressable.append(chunk + "\n");
}
}
public Progressable getpDialog() {
return progressable;
}
}
TA貢獻1921條經驗 獲得超9個贊
這里的問題是您的 Jdialog 框是模態的。每當彈出(或 JDialog)是setModal(true)EDT 線程被阻塞。這就是當使用 modal 彈出時用戶將無法執行任何操作的方式true。
您必須制作它setmodal(false),然后在彈出窗口中更新內容,然后再制作它setmodal(true)。
添加回答
舉報
