Java 无法在繁重的进程下更新Swing组件
我在一个匿名Java 无法在繁重的进程下更新Swing组件,java,multithreading,swing,event-dispatch-thread,invokelater,Java,Multithreading,Swing,Event Dispatch Thread,Invokelater,我在一个匿名SwingWorker线程下运行一个非常繁重的进程。同时,我使用进度条向GUI报告进度。然而,Swing线程正在使我陷入困境。它只是没有及时更新任何东西。我不知道该怎么做,因为我尝试从SwingWorker线程和外部更新GUI,但都拒绝工作 当繁重的工作线程运行时,如何可靠地更新Swing UI? 我尝试过的事情 这不起作用(无论是否在invokeLater命令中包装) 此外,尝试从并发测量线程更新UI不起作用: class LocalCompressor extends Swin
SwingWorker
线程下运行一个非常繁重的进程。同时,我使用进度条向GUI报告进度。然而,Swing线程正在使我陷入困境。它只是没有及时更新任何东西。我不知道该怎么做,因为我尝试从SwingWorker
线程和外部更新GUI,但都拒绝工作
当繁重的工作线程运行时,如何可靠地更新Swing UI?
我尝试过的事情
这不起作用(无论是否在invokeLater
命令中包装)
此外,尝试从并发测量线程更新UI不起作用:
class LocalCompressor extends SwingWorker<Void, Void> {
// [...]
public LocalCompressor(Compressor compressor) {
this.compressor = compressor;
// [...]
}
@Override
protected Void doInBackground() {
final Thread t1 = new Thread(new Runnable() {
@Override
public void run(){
compressor.compress();
}
});
final Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
t1.start();
while (t1.isAlive()) {
updateUI(compressor.getPercentDone());
}
}
});
t2.start();
return null;
}
// [...]
}
class LocalCompressor扩展SwingWorker{
// [...]
公共压缩机(压缩机){
这个。压缩机=压缩机;
// [...]
}
@凌驾
受保护的Void doInBackground(){
最终线程t1=新线程(新可运行(){
@凌驾
公开募捐{
compressor.compress();
}
});
最终螺纹t2=新螺纹(新可运行(){
@凌驾
公开募捐{
t1.start();
while(t1.isAlive()){
updateUI(compressor.getPercentDone());
}
}
});
t2.start();
返回null;
}
// [...]
}
你并没有真正使用你的SwingWorker。工作线程本身已经是线程。如果您可以将长时间运行的代码放入doInBackground()
,请将其放在那里。然后用实际进度调用publish(Integer)
,处理process(List)
-方法中得到的块。在process()中,您可以更新gui,它位于EDT上
编辑:
实际上,您现在正在做的是在几个while循环中进行轮询,这有点耗电。这就是为什么我认为在你的算法中,每次你得到一个百分比,或者每次循环开始新的一轮或类似的事情时,对你来说更好。你并不是真的在使用你的SwingWorker。工作线程本身已经是线程。如果您可以将长时间运行的代码放入
doInBackground()
,请将其放在那里。然后用实际进度调用publish(Integer)
,处理process(List)
-方法中得到的块。在process()中,您可以更新gui,它位于EDT上
编辑:
实际上,您现在正在做的是在几个while循环中进行轮询,这有点耗电。这就是为什么我认为算法中的事件对你来说更好,每次你得到一个百分比,或者每次循环开始新一轮或者类似的事情。我假设(你知道怎么回事)对LocalCompressor.execute()
的调用被阻塞了。如果是这样的话,while循环在完成之前不会运行,这样你就无法在UI上获得稳定的更新流
试一试这个或类似的东西:
LocalCompressor comp = new LocalCompressor(compressor);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
while (!compressionDone) {
int percent = compressor.getPercentDone();
progressBar.setValue(percent);
statusLabel.setText(percent);
}
}
});
comp.execute();
}
我假设(你知道这是怎么回事)对LocalCompressor.execute()
的调用被阻塞了。如果是这样的话,while循环在完成之前不会运行,这样你就无法在UI上获得稳定的更新流
试一试这个或类似的东西:
LocalCompressor comp = new LocalCompressor(compressor);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
while (!compressionDone) {
int percent = compressor.getPercentDone();
progressBar.setValue(percent);
statusLabel.setText(percent);
}
}
});
comp.execute();
}
在这里已经提供的答案和建议的基础上,这里有一种编码方法。我假设压缩器本身没有能力进行回调,但您可以要求它提供完成百分比 在swingworker线程(doInBackground)中,我们启动真正的压缩线程。然后在后台线程中启动轮询循环,以每秒更新几次UI。要通知UI线程,请调用publish。这将导致在事件线程中周期性地调用重写的方法进程。从这里我们可以安全地更新进度条和状态标签
public class LocalCompressor extends SwingWorker<Void, Integer>
{
private Compressor compressor;
public LocalCompressor(Compressor compressor)
{
this.compressor = compressor;
// [...]
}
@Override
protected void done()
{
System.out.println("Compression is done. Going to do something with it...");
}
@Override
protected void process(List<Integer> chunks)
{
for (Integer percent : chunks)
{
progressBar.setValue(percent);
statusLabel.setText(percent);
}
}
@Override
protected Void doInBackground() throws Exception
{
final Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
compressor.compress();
}
});
t1.start();
while (t1.isAlive())
{
int percentDone = compressor.getPercentDone();
publish(percentDone);
Thread.sleep(200);
}
return null;
}
}
public类LocalCompressor扩展SwingWorker
{
私人压缩机;
公共压缩机(压缩机)
{
这个。压缩机=压缩机;
// [...]
}
@凌驾
受保护的void done()
{
System.out.println(“压缩完成了,打算用它做点什么…”);
}
@凌驾
受保护的无效进程(列表块)
{
for(整数百分比:块)
{
progressBar.setValue(百分比);
statusLabel.setText(百分比);
}
}
@凌驾
受保护的Void doInBackground()引发异常
{
最终线程t1=新线程(新可运行()
{
@凌驾
公开募捐
{
compressor.compress();
}
});
t1.start();
while(t1.isAlive())
{
int percentDone=compressor.getPercentDone();
发布(完成百分比);
睡眠(200);
}
返回null;
}
}
在这里提供的答案和建议的基础上,这里有一种编码方法。我假设压缩器本身没有能力进行回调,但您可以要求它提供完成百分比
在swingworker线程(doInBackground)中,我们启动真正的压缩线程。然后在后台线程中启动轮询循环,以每秒更新几次UI。要通知UI线程,请调用publish。这将导致在事件线程中周期性地调用重写的方法进程。从这里我们可以安全地更新进度条和状态标签
public class LocalCompressor extends SwingWorker<Void, Integer>
{
private Compressor compressor;
public LocalCompressor(Compressor compressor)
{
this.compressor = compressor;
// [...]
}
@Override
protected void done()
{
System.out.println("Compression is done. Going to do something with it...");
}
@Override
protected void process(List<Integer> chunks)
{
for (Integer percent : chunks)
{
progressBar.setValue(percent);
statusLabel.setText(percent);
}
}
@Override
protected Void doInBackground() throws Exception
{
final Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
compressor.compress();
}
});
t1.start();
while (t1.isAlive())
{
int percentDone = compressor.getPercentDone();
publish(percentDone);
Thread.sleep(200);
}
return null;
}
}
public类LocalCompressor扩展SwingWorker
{
私人压缩机;
公共压缩机(压缩机)
class LocalCompressor extends SwingWorker<Void, Integer> {
// .....
// Your constructor here
// .....
@Override
protected Void doInBackground() throws Exception {
compress();
return null;
}
@Override
protected void process(List<Integer> chunks) {
for (Integer chunk : chunks) {
progressBar.setValue(chunk);
statusLabel.setText(chunk);
}
}
}
private void compress() {
// .....
publish(getPercentDone());
// .....
}