-1

Java 文档说:

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

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

文档进一步说:

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

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

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

4

4 回答 4

4

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

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

..独立程序不会发生同样的事情吗?

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

于 2013-03-10T06:55:25.870 回答
0

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

  1. 实例化一个 JFrame
  2. 使用此 Frame 作为参数构造小程序(调用 super() 并设置类变量的重载构造函数) 调用小程序的 init() 方法
  3. 使框架在屏幕上居中并可见(作为独立应用程序工作)

在 init() 方法中,除了其他 GUI 组件之外,我们还创建了菜单栏,如果在构造函数中设置了 Frame 的类变量(它在选择时调用 System.exit()),则将 JMenuItem 作为“Exit”放入.

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

于 2013-03-10T08:01:16.097 回答
0

看看下面的代码——它既可以用作小程序,也可以用作应用程序。方法 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);
}}
于 2013-03-10T10:23:49.373 回答
0

@trashgod所以我放入了一个非空的 start() 方法,并添加了一个 JPanel,它制作了一个旋转正方形(使用从 start() 开始的线程动画)。我仍然发现 init1() 和 init2() 的行为完全相同。小心向 OP(和我自己)解释为什么您更喜欢在这种情况下使用 invokeAndWait() 。

@Andrew我知道我对上面的答案不正确。请详细说明我为什么不对,以及正确答案是什么。我试图遵循您的一个答案,但链接已断开。

这是可编译的应用程序(是的,通常我会将其放入 3 个单独的类中,但在这里我们试图回答一个特定问题)。

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);
}}}
于 2013-03-10T17:22:07.603 回答