2012-09-05 25 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 *。 –