繁体   English   中英

Java JProgressBar不会通过setVisible显示(true)

[英]Java JProgressBar does not show up by setVisible(true)

我有下面的方法。

ProgressWindowJFrame的子类,其中包含JProgressBar

addProgress()增加JProgressBar的值。

如果我从另一个类的方法中调用此方法,则将显示ProgressWindow框架,但不会显示JProgressBar和框架中的某些JLabels 它们显示在最后一行( System.out.println("finish") )之后。

如果在包含该方法的类的主方法中调用此方法,则每个组件(Bar,标签...)都会立即显示。

如何正确显示窗口?

static void search(){
  ProgressWindow window = new ProgressWindow();
  window.setVisible(true);
  ExecutorService execs = Executors.newFixedThreadPool(Runtime
            .getRuntime().availableProcessors());
  Collection<Callable<Void>> processes = new LinkedList<>();
  for (int i = 0; i < 100; i++) {
    processes.add(new Callable<Void>() {
        @Override
        public Void call() throws Exception {
            progressWindow.addProgress(); // increment progress value
            return null;
        }
        });
    }
    try {
        execs.invokeAll(processes);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        execs.shutdown();
    }
    System.out.println("finish");

听起来您想要执行的操作是在Swing UI线程上调用setVisible,您可以使用invokeAndWaitinvokeLater进行此操作。

所以像这样:

final ProgressWindow window = new ProgressWindow();
SwingUtilities.invokeLater(new Runnable() {            
    @Override
    public void run() {
        window.setVisible(true);                
    }
});

主要问题是您似乎从事件调度线程的上下文调用search

发生此问题的原因是您正在使用execs.invokeAll ,它将阻塞直到所有callables都已运行完毕。

这意味着EDT无法处理事件队列中的新事件,包括重画事件,这就是为什么您的UI停滞不前的原因...

您现在要面对许多问题...

  1. 除EDT之外,请勿从任何线程更新/修改UI组件
  2. 您应出于任何原因阻止EDT
  3. 您似乎想知道搜索何时完成,因此您需要某种事件通知...

我们需要做的第一件事是通过某种方式通知搜索已完成,这意味着您不再可以依赖search后返回的信息...

public interface SearchListener {
    public void searchCompleted();
}

接下来,我们需要一个可互操作的search方法,该方法可构建UI并确保在其自己的Thread内启动搜索...

static void search(final SearchListener listener) {
  final ProgressWindow window = new ProgressWindow();
  window.setVisible(true);

  Thread t = new Thread(new Runnable() {
    @Override
    public void run() {
        search(listener, window);
    }
  });
  t.start();
}

然后我们需要修改原始search方法以利用SearchListener接口在搜索完成时提供通知...

static void search(final SearchListener listener, final ProgressWindow window){
  ExecutorService execs = Executors.newFixedThreadPool(Runtime
            .getRuntime().availableProcessors());
  Collection<Callable<Void>> processes = new LinkedList<>();
  for (int i = 0; i < 100; i++) {
    processes.add(new Callable<Void>() {
        @Override
        public Void call() throws Exception {
            // This method needs to ensure that 
            // what ever it does to the UI, it is done from within
            // the context of the EDT!!
            progressWindow.addProgress();
            return null;
        }
        });
    }
    try {
        execs.invokeAll(processes);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        execs.shutdown();
    }
    System.out.println("finish");
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            listener.searchCompleted();
        }
    });        
}

现在,如果没有addProgress的源代码,我可能会想使用

processes.add(new Callable<Void>() {
    @Override
    public Void call() throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                progressWindow.addProgress();
            }            
        });
        return null;
    }
    });
}

代替...

查看Swing中的并发以了解更多详细信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM