我有一个带进度条和文本区域的模态Jdialog。我正在启动一个Swing Worker来做一些后台任务,并使用发布进程更新jdialog中的文本区域。然而,在运行程序时,我观察到即使调用了进程方法,它仍然没有更新jdialog中的文本区域。此外,请注意,我正在关闭摇摆工人的完成方法中的jdialog,它工作正常。有人能告诉我为什么(SwingWorker的)进程方法的gui更新没有发生吗?
JDialog类-
public class ProgressDialog extends JDialog {
private static final long serialVersionUID = 1L;
private GridBagLayout gridBag;
private GridBagConstraints constraints;
private ProgressDialog.ProgressBar progressBar;
private JScrollPane scrollPane;
private JTextArea textArea;
ProgressDialog(Frame owner, String title, boolean modal, int numTasks) {
super(owner,title,modal);
gridBag = new GridBagLayout();
constraints = new GridBagConstraints();
this.progressBar = new ProgressDialog.ProgressBar();
this.progressBar.init(numTasks);
this.textArea = new JTextArea(10,30);
this.textArea.setEditable(false);
this.scrollPane = new JScrollPane(this.textArea);
this.scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
this.setLayout(gridBag);
constraints.gridx = 0;
constraints.gridy = 0;
gridBag.setConstraints(progressBar, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
constraints.insets = new Insets(10,0,10,0);
gridBag.setConstraints(scrollPane, constraints);
this.add(progressBar);
this.add(scrollPane);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setSize(400, 300);
this.setLocationRelativeTo(null);
}
class ProgressBar extends JProgressBar {
ProgressBar() {
}
void init(int numTasks) {
setMaximum(numTasks);
setStringPainted(true);
setValue(0);
}
void setProgress(int taskCompleted) {
int totalTasks = getMaximum();
setValue(taskCompleted);
setString(taskCompleted+"/"+totalTasks);
}
}
static long getSerialversionuid() {
return serialVersionUID;
}
GridBagLayout getGridBag() {
return gridBag;
}
GridBagConstraints getConstraints() {
return constraints;
}
ProgressDialog.ProgressBar getProgressBar() {
return progressBar;
}
JScrollPane getScrollPane() {
return scrollPane;
}
JTextArea getTextArea() {
return textArea;
}
}
SwingWorker类:
public class SwingWorkers {
static class ConnPool extends SwingWorker<Void, TaskType<String>>{
private ProgressDialog pDialog;
ConnPool(ProgressDialog pDialog) {
this.pDialog = pDialog;
}
protected Void doInBackground() throws Exception {
Runner<String> runner = new Runner<>();
Future<TaskType<String>> fut = runner.run(new Tasks.InitResources());
runner.shutDown();
while(!fut.isDone()) {
Thread.sleep(1000);
}
publish(fut.get());
return null;
}
protected void process(List<TaskType<String>> results) {
if(results.size() > 0) {
TaskType<String> lastResult = results.get(results.size()-1);
pDialog.getTextArea().append(lastResult.getTaskStatusMesg());
pDialog.getTextArea().append("\n");
pDialog.getProgressBar().setValue(results.size());
}
}
protected void done() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pDialog.dispose();
}
}
}
调用Jdialog和Swingworker的控制器代码-
JFrame parent = GUI.getInstance().getFrame();
ProgressDialog pDialog = new ProgressDialog(parent,"Working...",false,1);
pDialog.getTextArea().append("Initializing background tasks");
new SwingWorkers.ConnPool(pDialog).execute();
pDialog.setVisible(true);
我在某处读到,一旦模态Jdialog变得可见,EDT就会被阻止,直到它再次关闭?但是这仍然不能解释为什么SwingWorker中的完成方法能够关闭Jdialog。
编辑:我知道我只调用了一次进程方法(它应该在一次循环中)。在我可以让这个场景(进程方法的gui更新)工作后,我打算使用发布进程机制来执行更耗时的任务。
还要注意,sleep in done方法仅用于测试。我可以复制相同的问题,而不必在done方法中使用sleep方法。
匿名用户
这里的问题是你的Jdialog框是模态的。每当弹出(或JDialog)是setModal(true)时,EDT线程就会被阻塞。这就是为什么当弹出模态true
时,用户将无法进行任何操作。
您必须将其设置为setmodal(false)
,然后更新弹出窗口中的内容,然后再次设置为setmodal(true)
。
一个巨大的问题就在这里:
protected void done() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pDialog.dispose();
}
worker的done()
方法在EDT或事件调度线程上被调用,你知道当你睡眠这个线程时会发生什么——整个GUI进入睡眠状态,完全没有响应。如果您想延迟对话框的处理并保持GUI功能,请不要这样做,事实上,永远不要调用线程。在EDT上睡觉
。
相反,在大多数其他摇摆延迟策略中,使用摇摆计时器,例如,这样的东西(代码未测试):
protected void done() {
int timerDelay = 5000;
new Timer(timerDelay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
pDialog.dispose();
((Timer) e.getSource).stop();
}
}).start();
}
如果你不熟悉摆动计时器的使用,那么请查看摆动计时器教程
把你的线程放进去。sleep(5000)
在doInBackground()方法的末尾,就在
返回null之前
另一个问题:您正在使用publish/process方法对,但只使用了一次,这违背了它的目的。也许你想在轮询while循环中调用publish?当然,您只能调用一次
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;
}
}
问题内容: 您好,我想知道从swingworkerthread向jtextarea添加文本的最佳方法是什么,我创建了另一个类,Threadsclass()。execute()调用了jbutton。并且线程与此代码并行运行 现在id要做的是将x的值添加到主gui上的文本区域,任何想法都值得赞赏。 问题答案: JavaDocs有一个很好的例子 看一下发布和处理 潜在的意图是,您仅需要从事件调度线程中更
问题内容: 我有主GUI线程,其中有一个JprogressBar,并且正在实现ProprtyChangeListener。 当按下按钮时,扩展SwingWorker的其他类将开始执行并执行一系列可能很长的计算。我需要A类中的进度条以根据B类中的变量来呈现进度。 我的代码在下面(我所有失败的尝试都可能有点混乱…) 将不胜感激。 GUI类别: 计算类: 编辑 原始问题仍然存在。出于某种原因,进度条仍然
问题内容: 我对SwingWorker和Java GUI有疑问。 我有几类,其处理的信息,我们可以给他们打电话,和。此处理可能需要很长时间。 这些都是的子类,但是本身并不是直接调用的(这些类使用继承自的方法。为了使EDT自由绘制进度条,在保持对象层次结构时最好的使用方法是什么?是否具有包装器类,并且有其调用?即使不扩展,它仍然可以按我期望的那样工作吗? 编辑:澄清我的问题,即使他们已经是子类,我如
问题内容: 我使用SwingWorker使用Java Swing API制作进度条。 我有一个扩展SwingWorker的类 第二节课(我正在写一篇) 当我在第二个测试器中启动时,在进度条出现之前会显示消息“找不到方法”,而在以后的情况下我希望出现该消息。该怎么办? 问题答案: 将启动一个背景(从中调用该方法),程序将继续执行。 不是阻塞方法,这是使用它的原因,因此您不要阻塞事件调度线程 您可以使
这是具有状态(值和项)的父组件。我试图将值状态作为道具传递给子组件。当我点击按钮时,在render方法中执行的代码正在执行切换。但当我调用componentDidMount中的list函数时,切换不起作用,但执行了click事件。 这是我的子组件,其中状态作为道具传递 我知道组件didmount只执行一次。但是除了在render方法中直接编写JSX之外,如何使它工作呢
我正在尝试将chromedriver从2.30升级到2.35。不过在我< code>brew安装chromedriver之后,默认的chromedriver还是2.30。如果我重做brew,它会告诉我已经安装了2.35版本,但当我使用< code > chrome driver-version 时,它仍然显示2.30。有人能告诉我为什么吗?我能知道这个brew安装在哪里吗? 谢谢! < code