如何在 Java 中正确实现玻璃面板?

How to properly implement a glass pane in Java?

我正在尝试为我的大型 Swing 程序添加一个精美的 InfiniteProgressPanel 作为 GlassPane。但是,它没有出现。它看起来类似于:

...
InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
setGlassPane(glassPane);
...
glassPane.start();
doSomeStuff();
glassPane.stop();
...

我相信它 运行在同一个线程中作为它打算掩盖的漫长过程。我承认,我对线程的了解还不够,我可能应该弄清楚如何 运行 InfiniteProgressPanel GlassPane 在一个单独的线程中,以及在它自己的线程中的长进程。

更新 swing 时 UI 您需要在 Swing 的事件线程中进行。这包括创建组件或任何类型的进度更新。您可以通过 SwingUtilities.invokeLater(Runnable) 方法执行此操作。

因此,如果在后台线程中,您应该创建玻璃面板并通过 invokeLater 显示它。从您的长 运行 进程线程对玻璃面板的任何进度更新都应通过 invokeLater 完成。

线程本身就是同一个程序中的不同进程。

在 java 中,有许多不同的线程类型,您需要的线程类型是 SwingWorker

来自 Oracle 文档的 definition/use 是:

When a Swing program needs to execute a long-running task, it usually uses one of the worker threads, also known as the background threads. Each task running on a worker thread is represented by an instance of javax.swing.SwingWorker. SwingWorker itself is an abstract class; you must define a subclass in order to create a SwingWorker object; anonymous inner classes are often useful for creating very simple SwingWorker objects.

如您所见,这就是您所需要的; 后台线程。


final InfiniteProgressPanel glassPane;

...

class GlassPaneHandler extends SwingWorker<String, Object> {
    @Override
   public String doInBackground() {
       glassPane.start();
       return setUpPaneAndStuff();
   }

    @Override
   protected void done() {
       try {
           glassPane.stop();
       } catch (Exception e) {  } //ignore
   }

   private void setUpPaneAndStuff() {
       //code
   }
}

...

(new GlassPaneHandler()).execute(); //place this in your code where you want to initiate the pane

更多请看:http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html

一定要:

  • 运行 所有长 运行ning 代码都在后台线程中。这是必须的。

    Sounds great! How do I do so? Encapsulate all of the long-running code inside of an .invokeLater method? And should that be SwingUtilities.invokeLater or EventQueue.invokeLater? And what's the difference, anyway?

    • 不,通过使用 SwingUtilities.invokeLater(new MyRunnable) 你做的恰恰相反——你保证 long-运行ning 代码将被调用 on Swing 事件线程——与您想要的完全相反。而是使用 SwingWorker 的 doInBackground() 方法来 运行 长 运行ning 代码。关于你的第二点,SwingUtilities.invokeLaterEventQueue.invokeLater没有任何区别。
  • 在 Swing 事件线程上进行大部分 Swing 调用,也是必须

    Fantastic! Again, how do I do so? Same thing as above?

    • 如上所述使用 SwingUtilities.invokeLater(new MyRunnable),或者如果您使用的是 SwingWorker,则使用其 publish/process 方法对,SwingWorker 教程将向您展示。
  • 在玻璃面板上调用 setVisible(true),因为根据 JRootPane API,默认情况下所有玻璃面板都是不可见的。

    Romain Guy's InfiniteProgressPanel doesn't seem to need a setVisible(true). It appears when the InfiniteProgressPanel.start() method is called.

    • 我不熟悉这个,你有link吗?