如何在 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.invokeLater
和EventQueue.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吗?
我正在尝试为我的大型 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.invokeLater
和EventQueue.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吗?