简体   繁体   English

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

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

I have a method like below. 我有下面的方法。

ProgressWindow is a sub class of JFrame containing JProgressBar . ProgressWindowJFrame的子类,其中包含JProgressBar

addProgress() increments a value in the JProgressBar . addProgress()增加JProgressBar的值。

If I call this method from a method in another class, a frame of ProgressWindow will show up but not JProgressBar and some JLabels inside the frame. 如果我从另一个类的方法中调用此方法,则将显示ProgressWindow框架,但不会显示JProgressBar和框架中的某些JLabels They show up after the last line ( System.out.println("finish") ). 它们显示在最后一行( System.out.println("finish") )之后。

If I call this method in a main method in the class containing this method, then every component (Bar, labels...) instantly shows up. 如果在包含该方法的类的主方法中调用此方法,则每个组件(Bar,标签...)都会立即显示。

What can I do for showing the window correctly? 如何正确显示窗口?

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");

Sounds like you what you're wanting to do is invoke the setVisible on the Swing UI thread, you can do this with invokeAndWait or invokeLater . 听起来您想要执行的操作是在Swing UI线程上调用setVisible,您可以使用invokeAndWaitinvokeLater进行此操作。

So something like: 所以像这样:

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

The main problem is you seem to be calling search from the context of the Event Dispatching Thread. 主要问题是您似乎从事件调度线程的上下文调用search

The problem occurs because you are using execs.invokeAll which blocks until all the callables have finished running. 发生此问题的原因是您正在使用execs.invokeAll ,它将阻塞直到所有callables都已运行完毕。

This means that the EDT is unable to process new events in Event Queue, including repaint events, this is why your UI is coming to a stand still... 这意味着EDT无法处理事件队列中的新事件,包括重画事件,这就是为什么您的UI停滞不前的原因...

There are a number of issues you are now going to face... 您现在要面对许多问题...

  1. You should never update/modify a UI component from any thread other than the EDT 除EDT之外,请勿从任何线程更新/修改UI组件
  2. You should block the EDT for any reason 您应出于任何原因阻止EDT
  3. You seem to want to know when the search is complete, so you know need some kind of event notification... 您似乎想知道搜索何时完成,因此您需要某种事件通知...

The first thing we need is some way to be notified that the search has completed, this means you can no longer rely on search returning when the search is complete... 我们需要做的第一件事是通过某种方式通知搜索已完成,这意味着您不再可以依赖search后返回的信息...

public interface SearchListener {
    public void searchCompleted();
}

Next we need an intermeditate search method that builds the UI and ensure that the search is launched within it's own Thread ... 接下来,我们需要一个可互操作的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();
}

Then we need to modify the original search method to utilise the SearchListener interface to provide notification when the search is complete... 然后我们需要修改原始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();
        }
    });        
}

Now, without the source code for addProgress , I might be tempted to use 现在,如果没有addProgress的源代码,我可能会想使用

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

Instead... 代替...

Take a look at Concurrency in Swing for more details 查看Swing中的并发以了解更多详细信息

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

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