2011-12-21 75 views
3

什麼是處理SWT殼的正確方法?我使用Dialog API文檔中給出的模板創建了一些成功的對話框。該SWT API for Dialog says如何處理SWT殼(和對話框)?

爲用戶自定義對話框的基本模板通常看起來是這樣的 :

public class MyDialog extends Dialog { 
     Object result; 

     public MyDialog (Shell parent, int style) { 
       super (parent, style); 
     } 
     public MyDialog (Shell parent) { 
       this (parent, 0); // your default style bits go here (not the Shell's style bits) 
     } 
     public Object open() { 
       Shell parent = getParent(); 
       Shell shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); 
       shell.setText(getText()); 
       // Your code goes here (widget creation, set result, etc). 
       shell.open(); 
       Display display = parent.getDisplay(); 
       while (!shell.isDisposed()) { 
         if (!display.readAndDispatch()) display.sleep(); 
       } 
       return result; 
     } 
} 

我已經創建對話框不具有Windows自己的任務欄圖標,正如我期望的一個Dialog。我現在想創建一些shell,如果我理解正確在Windows上接收他們自己的任務欄條目?

與上述API文檔中給出的指示相反,我也看到an article,這似乎表明API文檔中顯示的具有while循環是錯誤的方法。該文章改爲建議使用close事件偵聽器來處置Shell。

什麼是正確的方式處理SWT貝殼(而同時在主題上,對話框以及)?

回答

10

希望我能幫忙解釋一下這裏發生了什麼。

Dialog基本上只是一個方便的子類,因爲Shell本身不應該被子類化。如果您願意,您可以根本不使用Dialog來創建shell。在這種情況下,您的MyDialog類是其他人可以用來反覆打開同一類型對話的類。

這段代碼驅動SWT事件循環只要殼是開放的(點擊外殼上的關閉按鈕部署默認的shell):

  while (!shell.isDisposed()) { 
        if (!display.readAndDispatch()) display.sleep(); 
      } 

你必須定期調用Display.readAndDispatch保持你的SWT應用程序「鎖定」。基本上它會導致您的應用程序正確處理來自操作系統的所有傳入事件(鍵盤和鼠標事件,重繪事件等)。 readAndDispatch基本上從應用程序的事件隊列中獲取事件並調用正確的偵聽器。在Eclipse RCP應用程序中,工作臺通常負責「抽取」事件循環,而不必混淆它。 Here's a little more info about the event loop.

的目的,「手動」抽在此背景下,事件循環是防止MyDialog.open從而外殼沒有設置返回,但仍然保持從「掛起」的應用程序。如果你的MyDialog.open方法試圖等待shell被釋放,但它沒有抽取事件循環,你的應用程序將會「鎖定」,因爲沒有事件循環運行,shell就沒有辦法被通知它應該處置!

可以不使用此模式創建殼。下面是打開一噸炮彈一下子一個非常簡單的SWT應用程序的例子,只要其中至少有一個是仍處於打開狀態繼續運行(我省略了包聲明和進口):

public class Shells { 
    private static int numDisposals = 0; 

    public static void main(String[] args) { 
     Display d = Display.getDefault(); 

     for (int i = 0; i < 5; i++) { 
      Shell s = new Shell(d); 
      s.open(); 
      s.addDisposeListener(new DisposeListener() { 
       @Override 
       public void widgetDisposed(DisposeEvent arg0) { 
        numDisposals++; 
       } 
      }); 
     } 

     while (numDisposals < 5) { 
      while (!d.readAndDispatch()) { 
       d.sleep(); 
      } 
     } 
    } 
} 

請注意,我爲每個外殼添加一個DisposeListener,以便在關閉外殼時採取一些措施。您還可以使用IShellListener直接偵聽關閉事件,甚至實際防止它(例如,如果shell包含未保存的工作,則可能需要執行此操作)。下面是一個惱人的修改到啓動5個彈的第一個程序,並隨機阻止您關閉它們:

public class Shells { 
    private static Random r = new Random(); 
    private static int numDisposals = 0; 

    public static void main(String[] args) { 
     Display d = Display.getDefault(); 

     for (int i = 0; i < 5; i++) { 
      Shell s = new Shell(d); 
      s.open(); 
      s.addShellListener(new ShellAdapter() { 
       @Override 
       public void shellClosed(ShellEvent e) { 
        boolean close = r.nextBoolean(); 
        if (close) { 
         System.out.println("Alright, shell closing."); 
        } else { 
         System.out.println("Try again."); 
        } 
        e.doit = close; 
       } 
      }); 
      s.addDisposeListener(new DisposeListener() { 
       @Override 
       public void widgetDisposed(DisposeEvent arg0) { 
        numDisposals++; 
       } 
      }); 
     } 

     while (numDisposals < 5) { 
      while (!d.readAndDispatch()) { 
       d.sleep(); 
      } 
     } 
    } 
} 

希望這有助於使事情更清楚!


編輯補充:我不能完全肯定,爲什麼你沒有得到你的shell在Windows任務欄項目,但我懷疑它有話跟你傳遞到外殼的風格標誌構造函數。我的示例中的shell沒有樣式標誌,它們都有一個任務欄圖標。

+0

感謝這非常豐富的答案。關於任務欄圖標:我已將「主窗口」設置爲我的對話框的父級。當您將另一個shell作爲父項傳遞給新的shell構造函數時,那麼新的shell將不會收到任務欄圖標,並且新的shell始終位於其父項之上(以免被忽略)。只有顯示屏作爲其父母的外殼纔會顯示在任務欄上(Windows 7)。至少,這是我的測試所暗示的。 – Buttons840 2011-12-22 18:04:04