编程语言
首页 > 编程语言> > java – 为什么InvokeLater导致我的JFrame无法正确显示?

java – 为什么InvokeLater导致我的JFrame无法正确显示?

作者:互联网

好的,我已经在网上阅读了一个搜索过的内容,但我还没有找到问题的解决方案,也许我错过了一些简单的东西,因此我在这里……

我有一个相当大的项目,处理维修业务的工单.这是所有数据库连接,许多页面的代码和类.但我只是在前端添加了一小段代码,实质上是在我们的笔记区域中检查新消息.

无论如何,我显示一个带有两个JLabel的简单JFrame,而一个单独的线程查询数据库.这一切都发生在程序的开始.问题是我的小“请等待”JFrame提出了它的框架但没有胆量,没有背景,没有JLabel,在等待期间(这是程序加载的其余部分,而不是数据库线程),显示后,但是到那时它错过了它的观点.

我写了以下示例程序.它显示一个简单的JFrame(CheckingMessagesGUI:一个带有两个JLabel的JFrame,仅此而已)休眠5秒然后显示Example(主程序)JFrame,然后在这个例子中立即关闭(System.exit(0)),当然我的真实程序继续做更多.我发现invokeLater似乎导致了这个问题.一旦睡眠定时器用完,窗口就会显示,但显示它的代码是在Thread.sleep命令之前给出的,应该按照那个顺序完成吗?

我的问题是为什么invokeLater会导致我的JFrame无法正确显示?

我的理解是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是否已经完全绘制了?这就是问题所在.

解决方法:

invokeLater在Event Dispatch Thread中运行Runnable,它也用于更新GUI.
你的睡眠阻塞了这个线程,所以GUI也没有得到服务,在你从invokeLater代码返回之前不能做任何更新.
这就是为什么你不应该在这个线程中做任何长(耗时)的计算.它们应该在不同的(新)线程中完成.

The Event Dispatch Queue

Tasks on the event dispatch thread must finish quickly; if they don’t, unhandled events back up and the user interface becomes unresponsive.

您的代码可以更改为(未测试):

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类中显示“please wait”(参见注释),但不是.
这与GUI的工作方式有关.如果调用相应的(Swing)方法(draw,setText,setLocation,…),它不会直接更改显示内容.它只是在事件队列中排队一个事件. Event Dispatch Thread(应该是)唯一读取此队列并处理事件的Thread.只要它被阻止 – 在这种情况下通过睡眠 – 将不会显示对GUI的任何更改. GUI被冻结.

EDIT2:
invokeLater将Runnable附加到队列的末尾,以便在处理完所有挂起事件后由EDT执行后,将执行invokeLater调用之后的下一个命令.
invokeAndWait与上面相同,但实际的Thread阻塞直到EDT执行Runnable(在挂起事件之后),也就是说,invokeAndWait之后的命令只会在执行提交的Runnable之后启动.

标签:java,swing,awt,invokelater
来源: https://codeday.me/bug/20190522/1151416.html