Java 为什么invokeAndWait()更适合小程序而不是独立应用程序?

Java 为什么invokeAndWait()更适合小程序而不是独立应用程序?,java,swing,applet,invokelater,invokeandwait,Java,Swing,Applet,Invokelater,Invokeandwait,java文档说: 在小程序中,必须使用invokeAndWait()从init()方法启动GUI创建任务;否则,init()可能会在创建GUI之前返回,这可能会导致web浏览器启动小程序时出现问题 如果init()在创建GUI之前返回,会有什么问题?浏览器可能会出现什么样的问题 文件还说: 在任何其他类型的程序中,调度GUI创建任务通常是初始线程做的最后一件事,因此不管它使用invokeLater()还是invokeAndWait() GUI创建任务作为最后一件事是如何改变任何事情的?此外,它还

java文档说:

在小程序中,必须使用invokeAndWait()从init()方法启动GUI创建任务;否则,init()可能会在创建GUI之前返回,这可能会导致web浏览器启动小程序时出现问题

如果
init()
在创建GUI之前返回,会有什么问题?浏览器可能会出现什么样的问题

文件还说:

在任何其他类型的程序中,调度GUI创建任务通常是初始线程做的最后一件事,因此不管它使用invokeLater()还是invokeAndWait()

GUI创建任务作为最后一件事是如何改变任何事情的?此外,它还提到了通常的实践,如果GUI创建不是初始线程完成的最后一个任务,那么使用
invokeAndWait()
还是
invokeLater()

我想我明白他们想说什么,但我仍然想确定,因此,我发布了这个问题。 提前谢谢

如果
init()
在创建GUI之前返回,会有什么问题?浏览器可能会出现什么样的问题

我主要关心的是在组件创建结束之前调用
start()
方法。如果在start方法中引用组件,这将导致出现
NullPointerException

…独立程序就不能发生同样的事情吗


桌面应用程序没有
start()
方法。该方法是的一部分,但不是应用程序的一部分。

我将通过一个示例告诉您我的经验-假设我们有一个小程序(扩展JApplet),带有一个JMenuBar,有两个构造函数(一个调用super(),另一个调用this(),并根据其参数设置一个框架)。我们在类中还有一个main方法(applet不需要)

  • 显示一个JFrame
  • 将此框架作为参数构造小程序(调用super()并设置类变量的重载构造函数)调用小程序的init()方法
  • 使框架在屏幕上居中且可见(作为独立应用程序工作)
  • 在init()方法中,除了其他GUI组件之外,我们还创建菜单栏,如果在构造函数中设置了框架的类变量(选中时调用System.Exit()),则将JMenuItem作为“Exit”放入


    现在,invokeAndWait()机制(如教程中所述)可以作为小程序正常工作,因为小程序UI由单独的线程控制。作为一个应用程序运行,当我们调用System.exit()方法时,我们将遇到异常,因为当UI线程想要退出时,主线程将尝试挂起变量。如果我们从cmd/shell启动应用程序,读取这些JVM错误是很烦人的。这可能是不建议将其用于应用程序的一个原因。

    请查看以下代码-它既可以作为小程序也可以作为应用程序使用。方法init1()和init2()创建相同的UI。两者都有效。init2()创建一个单独的事件调度线程,不与浏览器中的任何其他线程竞争,建议用于小程序。但是,当单击“退出”按钮作为独立应用程序运行时,这会导致偶尔出现异常。这就是为什么建议应用程序使用init1()。无论如何,这是我的理解,我可能错了。但这种解释/理由现在有意义吗

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class P4  extends JApplet implements ActionListener {
    
        private Frame frame;        // null/applet, non-null/application
    
        public P4 () {          super();            }
        public P4 (Frame f) {       this();     frame = f;  }
    
        public void init () {
    //      init1();        // better for application
            init2();        // better for applets
        }
    
        public void init1 () {
            createGUI();
        }
    
        public void init2 () {
            try {
                    javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        createGUI();
                    }
                    });
            } catch (Exception ex) {
                ex.printStackTrace();
        }}
    
        private void createGUI () {
            JPanel p = new JPanel();
            JButton b = new JButton ("Click to say Hello to the world");
            b.addActionListener (this);
            p.add (b);
            if (frame != null) {            // application
                b = new JButton ("Exit");
                b.addActionListener (this);
                p.add (b);
                p.setPreferredSize (new Dimension (400, 50));
            }
            getContentPane().add(p);
        }
    
        public void actionPerformed (ActionEvent e) {
            if ("Exit".equals (e.getActionCommand()))
                System.exit (0);
            JOptionPane.showMessageDialog (frame, "Hello, world!");
        }
    
        public void start () { }
        public void stop () { }
        public void paint (Graphics g) { 
            super.paint (g);
        }
    
        public static void main (String[] args) {
            JFrame fr = new JFrame ("Appletication");
            P4 p4 = new P4 (fr);
            p4.init();      // initialize GUI
            fr.add (p4);        fr.pack();      fr.setVisible (true);
    }}
    

    @所以我加入了一个非空的start()方法,并添加了一个生成旋转正方形的JPanel(使用从start()开始的线程设置动画)。我仍然发现init1()和init2()的行为完全相同。请向OP(和我自己)解释一下,为什么在本例中您更喜欢调用EANDWAIT()

    @安德鲁:我明白我对上面的回答不正确。请详细说明我为什么不对,以及正确答案是什么。我试着跟随你的答案,找到了一个断开的链接

    这是一个可编译的应用程序(是的,通常我会把它分为3个不同的类,但这里我们试图回答一个特定的问题)

    import java.awt.*;
    导入java.awt.event.*;
    导入javax.swing.*;
    公共类P4扩展JApplet实现ActionListener{
    私有帧帧;//null/applet,非null/application
    私人画家=新画家();
    公共P4(){super();}
    公共P4(帧f){this();帧=f;}
    公共void init(){
    //init1();//更适合应用程序
    init2();//更适合小程序
    }
    公共void init1(){
    createGUI();
    }
    公共void init2(){
    试一试{
    javax.swing.SwingUtilities.invokeAndWait(new Runnable()){
    公开募捐{
    createGUI();
    }
    });
    }捕获(例外情况除外){
    例如printStackTrace();
    }}
    私有void createGUI(){
    JPanel p=newjpanel(newborderlayout());
    JButton b=新JButton(“点击向世界问好”);
    b、 addActionListener(此);
    p、 加(b)“南方”);
    p、 添加(油漆工,“中心”);
    如果(frame!=null){//应用程序
    b=新的按钮(“退出”);
    b、 addActionListener(此);
    p、 加上(b)“北部”);
    }
    getContentPane().add(p);
    }
    已执行的公共无效操作(操作事件e){
    如果(“Exit”.equals(例如getActionCommand()))
    系统出口(0);
    JOptionPane.showMessageDialog(框架“你好,世界!”);
    }
    public void start(){new Thread(painter).start();}
    公共无效停止(){}
    公共空间绘制(图形g){
    超级油漆(g);
    }
    公共静态void main(字符串[]args){
    JFrame fr=新JFrame(“应用”);
    
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class P4  extends JApplet implements ActionListener {
    
        private Frame frame;        // null/applet, non-null/application
        private Painter painter = new Painter();
    
        public P4 () {          super();            }
        public P4 (Frame f) {       this();     frame = f;  }
    
        public void init () {
    //      init1();        // better for application
            init2();        // better for applets
        }
    
        public void init1 () {
            createGUI();
        }
    
        public void init2 () {
            try {
                    javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        createGUI();
                    }
                    });
            } catch (Exception ex) {
                ex.printStackTrace();
        }}
    
        private void createGUI () {
            JPanel p = new JPanel(new BorderLayout());
            JButton b = new JButton ("Click to say Hello to the world");
            b.addActionListener (this);
            p.add (b, "South");
            p.add (painter, "Center");
            if (frame != null) {            // application
                b = new JButton ("Exit");
                b.addActionListener (this);
                p.add (b, "North");
            }
            getContentPane().add(p);
        }
    
        public void actionPerformed (ActionEvent e) {
            if ("Exit".equals (e.getActionCommand()))
                System.exit (0);
            JOptionPane.showMessageDialog (frame, "Hello, world!");
        }
    
        public void start () {          new Thread (painter).start(); }
        public void stop () { }
        public void paint (Graphics g) { 
            super.paint (g);
        }
    
        public static void main (String[] args) {
            JFrame fr = new JFrame ("Appletication");
            P4 p4 = new P4 (fr);
            p4.init();      p4.start();     // initialize GUI
            fr.add (p4);        fr.pack();      fr.setVisible (true);
        }
    
        public class Painter extends JPanel implements Runnable {
            private int state, px[] = new int[4], py[] = new int[4];
    
            public Painter () {
                super();
                setPreferredSize (new Dimension (300, 200));
            }
    
            public void run () {
                for ( ; ; ) {
                    if (++state == 45)
                        state = 0;
                    repaint();
                    try {
                        Thread.sleep (25);
                    } catch (InterruptedException ex) {
            }}}
    
            public void paint (Graphics g) {
                int w = getWidth(), h = getHeight(),
                    cx = w/2, cy = h/2, halfD = (cx < cy) ? cx : cy;
                halfD -= 10;
                Graphics2D g2 = (Graphics2D) g;
                g2.setPaint (Color.white);      g2.fillRect (0,0,w,h);
                for (int i = 0 ; i < 4 ; i++) {
                    double theta = (i*90 + 2*state) * Math.PI / 180;
                    px[i] = (int) Math.round (cx + halfD * Math.cos (theta));
                    py[i] = (int) Math.round (cy - halfD * Math.sin (theta));
                }
                g2.setPaint (Color.red);
                g2.fillPolygon (px, py, 4);
    }}}