我正在设计一个简单的 JavaFX 表单。
首先,我加载 JavaFX 环境(并等待其完成),如下所示:
final CountDownLatch latch_l = new CountDownLatch(1);
try {
// init the JavaFX environment
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JFXPanel(); // init JavaFX
latch_l.countDown();
}
});
latch_l.await();
}
这很好用。 (之所以需要先这样加载JavaFX,是因为它主要是一个Swing应用程序,里面有一些JavaFX组件,但它们是稍后加载的)
现在,我想在启动时添加一个启动屏幕,并在 JavaFX 环境加载时显示它(实际上在屏幕上显示大约 5 秒钟,因为有 Logo 、商标等......我需要展示的应用程序)
所以我想出了一个 SplashScreen 类,它只在屏幕上显示一个 JWindow,如下所示:
public class SplashScreen {
protected JWindow splashScreen_m = new JWindow();
protected Integer splashScreenDuration_m = 5000;
public void show() {
// fill the splash-screen with informations
...
// display the splash-screen
splashScreen_m.validate();
splashScreen_m.pack();
splashScreen_m.setLocationRelativeTo(null);
splashScreen_m.setVisible(true);
}
public void unload() {
// unload the splash-screen
splashScreen_m.setVisible(false);
splashScreen_m.dispose();
}
}
现在,我希望启动画面能够加载并自动显示 5 秒。 同时,我也希望加载 JavaFX 环境。
所以我像这样更新了 CountDownLatch :
final CountDownLatch latch_l = new CountDownLatch(2); // now countdown is set to 2
final SplashScreen splash_l = new SplashScreen();
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// show splash-screen
splash_l.show();
latch_l.countDown();
// init the JavaFX environment
new JFXPanel(); // init JavaFX
latch_l.countDown();
}
});
latch_l.await();
splash_l.unload();
}
所以,它正在工作,但是启动画面只停留在 JavaFX 环境加载时,所以基本上它卸载得非常快(考虑到我编写的代码,这是正常的)。
如何在不卡住 EDT 的情况下显示启动屏幕至少 5 秒(如果 JavaFX 加载速度更快)?
谢谢。
最佳答案
最重要的问题是您阻塞了事件调度线程,这意味着它在被阻塞时无法显示/更新任何内容。同样的问题也适用于 JavaFX。
您还应该永远不要从各自的事件队列之外的任何其他地方进行更新。
现在,您可以通过多种方式来实现此目的,但 SwingWorker
可能是目前最简单的。
抱歉,这就是我对 JavaFX 的全部接触...
public class TestJavaFXLoader extends JApplet {
public static void main(String[] args) {
new TestJavaFXLoader();
}
public TestJavaFXLoader() throws HeadlessException {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Loader loader = new Loader();
loader.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state") && evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
System.out.println("Load main app here :D");
}
}
});
loader.load();
}
});
}
public class Loader extends SwingWorker<Object, String> {
private JWindow splash;
private JLabel subMessage;
public Loader() {
}
protected void loadSplashScreen() {
try {
splash = new JWindow();
JLabel content = new JLabel(new ImageIcon(ImageIO.read(...))));
content.setLayout(new GridBagLayout());
splash.setContentPane(content);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
subMessage = createLabel("");
splash.add(createLabel("Loading, please wait"), gbc);
splash.add(subMessage, gbc);
splash.pack();
splash.setLocationRelativeTo(null);
splash.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
protected JLabel createLabel(String msg) {
JLabel message = new JLabel("Loading, please wait");
message.setForeground(Color.CYAN);
Font font = message.getFont();
message.setFont(font.deriveFont(Font.BOLD, 24));
return message;
}
public void load() {
if (!EventQueue.isDispatchThread()) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
loadSplashScreen();
}
});
} catch (Exception exp) {
exp.printStackTrace();
}
} else {
loadSplashScreen();
}
execute();
}
@Override
protected void done() {
splash.dispose();
}
@Override
protected void process(List<String> chunks) {
subMessage.setText(chunks.get(chunks.size() - 1));
}
@Override
protected Object doInBackground() throws Exception {
publish("Preparing to load application");
try {
Thread.sleep(2500);
} catch (InterruptedException interruptedException) {
}
publish("Loading JavaFX...");
runAndWait(new Runnable() {
@Override
public void run() {
new JFXPanel();
}
});
try {
Thread.sleep(2500);
} catch (InterruptedException interruptedException) {
}
return null;
}
public void runAndWait(final Runnable run)
throws InterruptedException, ExecutionException {
if (Platform.isFxApplicationThread()) {
try {
run.run();
} catch (Exception e) {
throw new ExecutionException(e);
}
} else {
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
lock.lock();
try {
Platform.runLater(new Runnable() {
@Override
public void run() {
lock.lock();
try {
run.run();
} catch (Throwable e) {
e.printStackTrace();
} finally {
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
});
condition.await();
// if (throwableWrapper.t != null) {
// throw new ExecutionException(throwableWrapper.t);
// }
} finally {
lock.unlock();
}
}
}
}
}
我找到了runAndWait
代码here
关于java - 如何显示启动画面,在后台加载数据,然后隐藏启动画面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14928586/