好的,我已经在网上搜索了所有内容,但还没有找到解决问题的方法,也许我缺少一些简单的东西,所以我在这里…
我有一个相当大的项目,处理维修业务的工单。它是所有与数据库连接的页面,其中包含许多页面的代码和类。但是我只是在前端添加了一小段代码,基本上检查了我们的注释区域中的新消息。
无论如何,我显示一个带有两个 JLabel 的简单 JFrame ,同时一个单独的线程查询数据库。所有这些都在程序开始时发生。问题是在等待期间(这是程序加载的其余部分,而不是数据库线程),我的小“请稍候” JFrame 出现了它的框架,但是没有胆量,没有背景,也没有 JLabel ,它显示了后缀,但是到那时,它已经失去了意义。 __
我编写了以下示例程序。它显示一个简单的 JFrame (CheckingMessagesGUI:一个带有两个 JLabel 的 JFrame ,仅此而已)睡眠5秒钟,然后显示Example(主程序) JFrame ,然后在此示例中立即关闭(),当然我的真实程序继续执行多很多。我发现这似乎是造成问题的原因。一旦睡眠计时器用完,将显示窗口,但是显示该代码的代码是在命令之前给出的,并且应该以正确的顺序执行吗? System.exit(0)``invokeLater``Thread.sleep
System.exit(0)``invokeLater``Thread.sleep
我的问题是为什么invokeLater导致我的 JFrame 无法正确显示?
invokeLater
我的理解invokeLater是,这样做的目的是使项目在正确的AWT事件线程上运行,这使我认为此窗口将正确绘制。无论如何,我确定我缺少明显的东西。我invokeLater在下面的代码中注释掉了该部分,它可以正确运行,如果将其放回原位,则不会…
提前谢谢了。
package javaapplication6; public class Example extends javax.swing.JFrame { public Example() { System.out.println("Example started"); setBounds(100,100,200,200); System.out.println("cmGUI instantiated"); CheckingMessagesGUI cmGUI = new CheckingMessagesGUI(); System.out.println("Set cmGUI visible"); cmGUI.setVisible(true); cmGUI.validate(); try { System.out.println("timer started"); Thread.sleep(5000); System.out.println("timer done"); } catch(InterruptedException e){ } System.exit(0); } public static void main(String[] args) { /*java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { */ System.out.println("Started"); System.out.println("example Instantiated"); Example example = new Example(); System.out.println("example visible"); example.setVisible(true); /* } }); */ } }
更新:为澄清起见,我意识到Thread.sleep()将阻止所有内容,但是在调用sleep之前我的CheckingMessagesGUI是否应该已经完全绘制好了?这就是问题。
Thread.sleep()
invokeLater在事件调度线程中运行Runnable,该线程也用于更新GUI。 您的睡眠正在阻塞此线程,因此GUI也不会得到 服务 ,直到您从invokeLater代码返回之前,无法进行任何更新。 这就是为什么您不应该在此线程中进行任何长时间(耗时的)计算的原因。它们应该在其他(新)线程中完成。
事件调度队列状态
事件分发线程上的任务必须快速完成;如果没有,则将备份未处理的事件,并且用户界面将无响应。
您的代码可以更改为(未经测试):
public Example(){ System.out.println("Example started"); setBounds(100,100,200,200); System.out.println("cmGUI instantiated"); CheckingMessagesGUI cmGUI = new CheckingMessagesGUI(); System.out.println("Set cmGUI visible"); cmGUI.setVisible(true); cmGUI.validate(); Thread thread = new Thread(new Runnable() { try { System.out.println("timer started"); Thread.sleep(5000); System.out.println("timer done"); } catch(InterruptedException e) { } System.exit(0); }); thread.start(); }
编辑:让我们更“深入”(这是我对Swing / AWT工作的看法)。 我想应该在CheckingMessagesGUI类中显示“请稍候”(请参阅注释),但不是。 这与GUI的工作方式有关。如果调用相应的(Swing)方法(draw,setText,setLocation等),它不会直接更改显示内容。它只是将事件在事件队列中排队。事件调度线程是(应该是)唯一读取此队列并处理事件的线程。只要它被阻止(在这种情况下为睡眠),就不会显示对GUI的更改。GUI被冻结。
EDIT2: invokeLater将Runnable 附加 到队列的末尾,以便在处理所有未决事件之后由EDT稍后执行,然后将执行invokeLater调用之后的下一个命令。 invokeAndWait与上面相同,但是实际的线程会阻塞,直到EDT执行Runnable(在挂起事件之后)为止,也就是说,invokeAndWait之后的命令仅在提交的Runnable执行之后才启动。
invokeAndWait