添加JFrame事件处理程序之前的滞后?

时间:2012-09-05 01:07:29

标签: java swing netbeans concurrency event-dispatch-thread

我正在开发一个简单的Java swing项目。这是主类的代码(名称已更改):

public class MainProg
{
    private static MainProg program; 

    //mainWin is a JFrame
    private MainWindow mainWin;

    //Event handler class which extends MouseAdapter
    private TrayManager trayMgr;


    public static void main(String[] args)
    {                
        program = new MainProg();
    }

    public MainProg()
    {
        mainWin = new MainWindow();
        trayMgr = new TrayManager();

        mainWin.startBtn.addMouseListener(trayMgr);

        mainWin.setVisible(true);
    }
}

很明显,当程序启动时,在main()中它会创建一个MainProg类的新实例,然后调用构造函数。在构造函数中,它创建了JFrame mainWin的新实例。然后它将事件处理程序附加到mainWin上的按钮。

在事件处理程序类trayMgr中,唯一的方法是mouseClicked(),它什么都不做 除了System.out.println('Clicked');

问题是,当我在Netbeans中运行此程序时,会立即显示JFrame,但我似乎必须在控制台中打印消息之前单击按钮2-3次。

这只是Netbeans的特定内容,还是我必须更改某些内容才能在窗口可见之前设置事件处理程序?

2 个答案:

答案 0 :(得分:5)

您的线程问题不太可能导致您当前的问题,但是存在问题的理论潜力,并且我已经看到一些与一些更敏感的外观和感觉相关的实际问题。很简单,您应该将启动GUI的代码排队到Swing事件线程中。你这样做:

public void main(String[] args) {
  SwingUtilities.invokeLater(new Runnable(
    public void run() {
      program = new MainProg();
    }
  ));
}

其他人建议使用invokeAndWait(...)而不是invokeLater(...),但这可能会有风险,尤其是如果您无意中从Swing事件线程本身进行此调用。根据您的情况,您最好使用invokeLater(...)

但同样,我认为您所显示的代码的主要问题是不恰当地使用了应该使用ActionListener的MouseListener。学习编写任何GUI库都非常棘手,因此,你不能假设任何东西。查看教程并向专家学习。此外,如果您正在考虑长期编写Swing,请考虑放弃NetBean的代码生成实用程序,并首先学习手动编写Swing代码。你不会后悔这样做。

答案 1 :(得分:3)

因为您问过,我在不同主题上发布了here is a Java SSCCE的代码。 invokeLater是一种在EDT上运行计算的方法。 (还有invokeAndWait,这在这里可以正常工作,但在某些其他条件下可能会导致死锁。)

事实上这个例子可能有点过于保守了。一些参考文献说你可以从主线程运行Swing,调用show()setVisible()。但是,当我尝试时,我有一个在Java 7下行为不端的程序。