2012-01-24 96 views
3

我讀「一個明確的指南SWT和JFace」,我試圖理解下面的代碼:事件無限循環SWT

public class MultipleListenersExample implements HelpListener, VerifyListener, 
    ModifyListener{ 

    // Constants used for conversions 
    private static final double FIVE_NINTHS = 5.0/9.0; 
    private static final double NINE_FIFTHS = 9.0/5.0; 

    // Widgets used in the window 
    private Text fahrenheit; 
    private Text celsius; 
    private Label help; 

    /** 
    * Runs the application 
    */ 
    public void run() { 
     Display display = new Display(); 
     Shell shell = new Shell(display); 
     shell.setText("Temperatures"); 
     createContents(shell); 
     shell.pack(); 
     shell.open(); 
     while (!shell.isDisposed()) { 
      if (!display.readAndDispatch()) { 
       display.sleep(); 
      } 
     } 
     display.dispose(); 
    } 

    /** 
    * Create the main window's contents 
    * @param shell the main window 
    */ 
    private void createContents(Shell shell) { 
     shell.setLayout(new GridLayout(3, true)); 

     // Create the label and input box for Fahrenheit 
     new Label(shell, SWT.LEFT).setText("Fahrenheit:"); 
     fahrenheit = new Text(shell, SWT.BORDER); 
     GridData data = new GridData(GridData.FILL_HORIZONTAL); 
     data.horizontalSpan = 2; 
     fahrenheit.setLayoutData(data); 

     // Set the context-sensitive help 
     fahrenheit.setData("Type a temperature in Fahrenheit"); 

     // Add the listeners 
     fahrenheit.addHelpListener(this); 
     fahrenheit.addVerifyListener(this); 
     fahrenheit.addModifyListener(this); 

     // Create the label and input box for Celsius 
     new Label(shell, SWT.LEFT).setText("Celsius:"); 
     celsius = new Text(shell, SWT.BORDER); 
     data = new GridData(GridData.FILL_HORIZONTAL); 
     data.horizontalSpan = 2; 
     celsius.setLayoutData(data); 

     // Set the context-sensitive help 
     celsius.setData("Type a temperature in Celsius"); 

     // Add the listeners 
     celsius.addHelpListener(this); 
     celsius.addVerifyListener(this); 
     celsius.addModifyListener(this); 

     // Create the area for help 
     help = new Label(shell, SWT.LEFT | SWT.BORDER); 
     data = new GridData(GridData.FILL_HORIZONTAL); 
     data.horizontalSpan = 3; 
     help.setLayoutData(data); 
    } 

    /** 
    * Called when user requests help 
    */ 
    public void helpRequested(HelpEvent event) { 
     // Get the help text from the widget and set it into the help label 
     help.setText((String) event.widget.getData()); 
    } 

    /** 
    * Called when the user types into a text box, but before the text box gets 
    * what the user typed 
    */ 
    public void verifyText(VerifyEvent event) {  
     // Assume you don't allow it 
     event.doit = false; 

     // Get the character typed 
     char myChar = event.character; 
     String text = ((Text) event.widget).getText(); 
     System.out.println(text); 

     // Allow '-' if first character 
     if (myChar == '-' && text.length() == 0) event.doit = true; 

     // Allow zero to nine 
     if (Character.isDigit(myChar)) event.doit = true; 

     // Allow backspace 
     if (myChar == '\b') event.doit = true; 
    } 

    /** 
    * Called when the user modifies the text in a text box 
    */ 
    public void modifyText(ModifyEvent event) {  
     // Remove all the listeners, so you don't enter any infinite loops 
     celsius.removeVerifyListener(this); 
     celsius.removeModifyListener(this); 
     fahrenheit.removeVerifyListener(this); 
     fahrenheit.removeModifyListener(this); 

     // Get the widget whose text was modified 
     Text text = (Text) event.widget; 

     try { 
      // Get the modified text 
      int temp = Integer.parseInt(text.getText()); 

      // If they modified Fahrenheit, convert to Celsius 
      if (text == fahrenheit) { 
       celsius.setText(String.valueOf((int) (FIVE_NINTHS * (temp - 32)))); 
      } else { 
      // Convert to Fahrenheit 
       fahrenheit.setText(String.valueOf((int) (NINE_FIFTHS * temp + 32))); 
      } 
     } catch (NumberFormatException e) { /* Ignore */ } 

     // Add the listeners back 
     celsius.addVerifyListener(this); 
     celsius.addModifyListener(this); 
     fahrenheit.addVerifyListener(this); 
     fahrenheit.addModifyListener(this); 
    } 

    /** 
    * The application entry point 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     new MultipleListenersExample().run(); 
    } 

} 

在「modifyText」方法,它消除了所有的聽衆(VerifyListenerModifyListener ),我不明白爲什麼?爲什麼會出現無限循環?

+0

嘗試將數據粘貼到攝氏'文本':-)使用'event.character'並不明智,因爲它只反映了添加到該字段的特定字符,而不是在字段中刪除,剪切或粘貼的字符。相反,首先計算新內容,假設編輯正常(基於event.start,event.end和event.text),然後分析此字符串。 –

回答

3

因爲你實際上在modifyText()方法修改文本字符串(值)的Text GUI元素,這種文本變化將觸發ModifyEvent,它再次調用modifyText()方法。因此,您必須刪除這些偵聽器,將文本更改爲適當的值並將這些偵聽器添加回來,否則會出現無限循環。

編輯(基於評論)

你說得對。首先在Text字段中輸入密鑰,並調用verifyText()。當此方法完成並且鍵入的文本被批准時,將調用modifyText()方法。如前所述,此方法將字段的文本字符串更改爲setText()方法。因此,在文本字符串實際上可以改變之前verifyText()被調用並批准新的文本字符串,然後去modifyText()方法,它應該實際上改變Text GUI元素中的文本,但它試圖調用setText()的元素並再次啓動該圓。

所以,你輸入一些數字爲Text元素(如'5'),verifyText()被調用,modifyText()如下,它調用setText()再次呼籲verifyText()modifyText(),它調用setText(),等等..哦,是的,無限循環這裏..

+0

謝謝你的回答! 但是...當我測試代碼時,無限循環出現在verifyText()中。 的事件(在我的意見)的順序是: 1)一個鍵被按下 2)之前出現在屏幕上的鍵的值,驗證完成 - > verifyText() 3)如果鍵的值正確 - > modifyText() 如果我評論刪除偵聽器的行,VerifyListener會再次觸發。爲什麼? – wallE

1

因爲否則,當你調用setText(),你會觸發ModifyListener,它將調用setText(),這將觸發ModifyListener ...

1

當你打算改變一些會導致監聽者事件觸發的東西時,你通常會刪除監聽者,這又會調用改變某個事物的方法。

編輯:刪除了比喻,因爲它很糟糕。