html> CSE190L Notes

CSE190L Notes for Wednesday, 4/18/07

There was still a fair amount of work to do in completing the sample program we have been studying, so I decided to devote one more lecture to it to make sure that we discussed all of the various issues.

We had added two new text fields to our program to allow a user to enter x and y coordinates for the text to be displayed by our colored panel. So we had to rewrite the setText method of the panel to be a setTextParameters method and we had to change updatePanel:

        private void updatePanel() {
            int x = Integer.parseInt(xEntry.getText().trim());
            int y = Integer.parseInt(yEntry.getText().trim());
            panel.setTextParameters(textEntry.getText(), x, y);
        }
We used the standard method Integer.parseInt to turn the string into an int. When you do that, it's prudent to call the trim method on the String to get rid of any extra whitespace. When we ran this program, it worked fairly well until we typed in something that wasn't an int. Then we got a long list of errors in the console window. It didn't halt the program because Swing catches such errors. But it's still not a good thing for the program to generate those kind of error messages.

So we spent some time discussing try/catch blocks. I won't repeat all of that here because the textbook has coverage, but I'll mention some highlights. There are two kinds of exceptions in Java:

The exception thrown by Integer.parseInt is NumberFormatException and it is a subclass of RuntimeException, so it us an unchecked exception. In our case we actually do want to catch it, so we needed to add a try/catch block to do so. We ended up adding two try/catch blocks, one for each of x and y, because we don't want a failure on x to cause us to not look at y:

        private void updatePanel() {
            int x, y;
            try {
                x = Integer.parseInt(xEntry.getText().trim());
            } catch (NumberFormatException e) {
                x = INITIAL_XY;
            }
            try {
                y = Integer.parseInt(yEntry.getText().trim());
            } catch (NumberFormatException e) {
                y = INITIAL_XY;
            }
            panel.setTextParameters(textEntry.getText(), x, y);
        }
There was some disagreement about exactly what the program should do when the user entered something illegal. One possibility is just to ignore an illegal input and that can be a reasonable approach. In the code above, we're setting it back to the original default value. That can be reasonable as well, but if you're going to do that, you should at least give some feedback to the user that you're ignoring their input. So we changed it to also beep at the user and to reset the text in the field to indicate that we're going back to the default value:

        private void updatePanel() {
            int x, y;
            try {
                x = Integer.parseInt(xEntry.getText().trim());
            } catch (NumberFormatException e) {
                x = INITIAL_XY;
                xEntry.setText("" + x);
                Toolkit.getDefaultToolkit().beep();
            }
            try {
                y = Integer.parseInt(yEntry.getText().trim());
            } catch (NumberFormatException e) {
                y = INITIAL_XY;
                yEntry.setText(y + "");
                Toolkit.getDefaultToolkit().beep();
            }
            panel.setTextParameters(textEntry.getText(), x, y);
        }
The most popular choice seemed to be the idea that we would revert to the previous legal value. But that's not such an easy thing to do. The frame doesn't know that value. Each time the user enters a new x or y, those values are passed along to the panel. If the user types something illegal, the frame has no memory of the previous legal value. There are several ways to fix this. We could, for example, introduce new fields for the frame to keep the "old legal x" and "old legal y" values. Or we could have new public methods in the panel class called getX and getY that would allow the frame to ask the panel for the current settings. Yet another way is to use what is called a JFormattedTextField which has this functionality built in. That's what I'm asking people to do in the programming assignment.

Then we spent some time talking about the fact that the text fields wake up only when the user hits the enter key in one of the fields. The fields do nothing if the user tabs to a new field or uses the mouse to move to some other part of the frame. To get that behavior, we had to add a focus listener. The idea of focus is that at any given point in time, a particular element of the frame has the focus, which means it is getting any keystrokes typed by the user. We defined a focus listener that would call the updatePanel method whenever the focus is lost

        FocusListener textFocusListener = new FocusAdapter() {
            public void focusLost(FocusEvent e) {
                updatePanel();
            }
        };
The FocusListener interface has two methods (focusGained and focusLost). We are only interested in overriding the focusLost method, so we again used the trick of extending the adapter class with just the method we are interested in. We then attached this listener to each of the text fields:

        textEntry.addFocusListener(textFocusListener);
        xEntry.addFocusListener(textFocusListener);
        yEntry.addFocusListener(textFocusListener);
As a final change, I pointed out that our code was really ugly. There are lots of cases like the lines of code above where we're doing the same thing three times in a row. We figured out that we could write a private method that would do most of the work necessary for a single text field. It required a lot of parameters because we had to tell it what to use for the initial text, the number of columns, and the label text, plus we had to tell it what panel to put these elements in and we had to tell it the action listener and focus listener to attach. But the result was a much more concise method that has the one-time operations in one method and the repeated operations in a separate method that is called three times. You should be looking for these kind of opportunities whenever you write redundant code.

The final version of the program is available from the class webpage as handout #10.

I then spent a few minutes demonstrating the next programming assignment. It is a two-week assignment and will be our last regular assignment. After this we have just the project.

I said that I am asking you to read chapter 9 of the textbook to learn several new widgets. In particular, I'm asking you to use a JFormattedTextField for the text fields, a JCheckBox and some JRadioButton objects. Most of these are fairly straightforward, although you run into a few bumps along the way as you try to figure out how to use these properly. You are encouraged to post messages to the message board if you are struggling with any of these details.

Because this assignment is coming out a few days late, the duedate has been extended to Wednesday. The bad thing about this is that our midterm is on Wednesday, May 2nd. So the program is due the same day as the midterm. This is not ideal, but I'm assuming that students will figure out a way to manage their time so that they can get this program done and still be able to take the midterm that day. There is a checkpoint due halfway through in which you have to complete approximately half of the code. The checkpoint will not be graded for style, just that you completed some significant part of the assignment that compiles and executes.


Stuart Reges
Last modified: Fri Apr 20 10:53:46 PDT 2007