事件无限循环SWT

时间:2012-01-24 21:50:19

标签: java swt

我正在阅读“SWT和JFace的明确指南”,我正在尝试理解以下代码:

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),我不明白为什么?为什么会出现无限循环?

3 个答案:

答案 0 :(得分:3)

因为您实际上是在modifyText() GUI元素的Text方法中修改文本字符串(值),所以此文本更改将触发ModifyEvent再次调用modifyText()方法。因此,您必须删除这些侦听器,将文本更改为适当的值并将这些侦听器添加回来,否则会发生无限循环。

编辑(根据评论)

你是对的。首先,您在Text字段中键入密钥,然后调用verifyText()。当此方法完成并且键入的文本被批准时,将调用modifyText()方法。正如我之前所说,此方法通过Text方法更改setText()字段的文本字符串。因此,在实际更改文本字符串之前调用verifyText()并批准新的文本字符串,然后转到modifyText()方法,该方法应该实际更改Text GUI元素内的文本,但它会尝试调用元素的setText()并再次启动圆圈。

因此,您在Text元素中键入了一些数字(如'5'),verifyText()被调用,modifyText()跟随,它调用setText()调用{再次{1}}和verifyText(),它会调用modifyText(),依此类推......哦,是的,无限循环就在这里..

答案 1 :(得分:1)

否则,当您拨打setText()时,您会触发ModifyListener,会调用setText(),这会触发ModifyListener ...

答案 2 :(得分:1)

当您要更改会导致侦听器事件触发的内容时,通常会删除侦听器,而这又会调用再次更改该内容的方法。

编辑:删除了类比,因为它非常糟糕。