I am reading “A Definite Guide to SWT and JFace” and I am trying to understand the following code:
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();
}
}
In “modifyText” method it removes all the listeners (VerifyListener and ModifyListener) and I don’t understand why? Why an infinite loop appears?
Because you’re actually modifying text string (value) in
modifyText()method ofTextGUI element, this change of text will triggerModifyEventwhich callsmodifyText()method again. So you have to remove those listeners, change text to appropriate value and add those listeners back, otherwise infinite loop occurs.EDIT (based on comments)
You’re right. First you type a key in
Textfield andverifyText()is called. When this method finish and typed text is approved,modifyText()method is called. And as I said previous, this method changes text string ofTextfield bysetText()method. So before the text string could be actually changedverifyText()is called and approves the new text string, then goes tomodifyText()method which should actually change the text insideTextGUI element, but it tries to callsetText()of the element and starts the circle again.So, you type some number into
Textelement (like'5'),verifyText()is called andmodifyText()follows, it callssetText()which callsverifyText()andmodifyText()again, it callssetText(), and so on.. Oh yeah, infinite loop is here..