2012-09-05 67 views
1

我正在开发一个简单的Java swing项目。这是主类的代码(名称变更):添加JFrame事件处理程序之前的延迟?

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

任何你可以包括[SSCCE](http://sscce.org/)的机会来证明这个问题? – tenorsax

+0

Netbeans不会更改程序的运行方式。你的代码也是不正确的,因为它从EDT以外的线程调用Swing。这可能是造成这个问题的原因。如果您向我们展示SSCCE为@Max表示我们可能会提供帮助。 – Gene

+0

@Gene我如何创建一个SSCCE?不过我敢肯定的是你所提到的重比事件循环的线程上,就是这个问题。你能详细说明一下吗? –

回答

5

你的线程问题是不太可能一个是导致你目前的问题,但有理论潜力的问题,我已经看到了一些比较敏感的外观和感觉相关的一些实际问题。非常简单,您应该将启动GUI的代码放到Swing事件线程中。您可通过执行此操作:使用invokeAndWait(...)代替invokeLater(...)推荐

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

别人但这是有风险的,特别是如果你在不经意间使从Swing事件中该调用线程本身。对于你的情况,你最好使用invokeLater(...)

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

+0

问题。因此,当这段代码运行时,它将如下所示:MainProg() - > JFrame() - > Jframe.initComponents()(这是所有UI组件都设置并添加到Jframe的地方)。这是你的意图吗? –

+2

我不得不第二个建议你先学习如何手动编写Swing。我有相当多的这样做,并且刚刚开始学习如何使用NetBeans GUI Builder。我在Stackoverflow的许多最近的Java问题都是关于使用GUI Builder的。总的来说,我发现它并不可怕,而且很可能会远离将来的项目使用它。 –

+0

@ClickUpvote由于线程问题,调用堆栈比您声明的要复杂一点。最终调用run(),然后调用MainProg()构造函数等。 –

3

既然你问了,我把代码here is a Java SSCCE放在不同的主题上。 invokeLater是在EDT上运行计算的一种方式。 (也有invokeAndWait,在这里可以正常工作,但在其他一些情况下可能会导致死锁。)

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

+0

**没有**,你几乎从不应该使用'invokeAndWait(...)'。更好地使用'invokeLater(...)'。我知道的唯一例外情况可能是启动JApplet时,但就是这样。 OP正在启动一个JFrame,所以这个建议是错误的。请改变它。 –

+0

如果你给我一个支持这个断言的参考,将会这样做。我从来没有见过长时间搜索Swing文档的东西。在这里,'invokeLater'阻止主线程,无论如何都不允许进行进一步的UI工作。在我发布的例子中,'invokeLater'将让主线程继续执行几条指令来等待EDT退出。执行路径没有实质性差异。但是,然后,我很高兴被证明是错误的,而不仅仅是简单的**以粗体显示**。 – Gene

+0

我知道的主要问题是,您可以在任何线程上调用invokeLater,而无法在EDT上调用invokeAndWait。如果你想要的文档,只需检查* SwingUtilities API *。 –