CSE190L Notes for Monday, 4/16/07

We picked up where we left off in Friday's lecture. We were working on adding an action listener for the text field:

        JTextField textEntry = new JTextField(INITIAL_TEXT, 30);
        textEntry.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                // ...
            }
        });
I pointed out that often in a case like this it makes sense to introduce a private method in the frame class that is called by the action listener, so we decided to have a private method called updatePanel:

            JTextField textEntry = new JTextField(INITIAL_TEXT, 30);
            textEntry.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    updatePanel();
                }
            });
Our initial version of updatePanel was fairly simple. We just wanted to have it tell the panel to change its text. This required us to make some modifications to the panel class so that it kept track of the string to display and so that it had an setText method that we could call from the frame. Then we wrote this code in the frame:

        private void updatePanel() {
            panel.setText(textEntry.getText());
        }
Notice that we call the getText method of the text field to get the String in the field. This meant that we couldn't have the text field as a local variable. We defined it as a field instead and found that we got a NullPointerException for the line of code above. That's because we accidentally had both a local variable and a field called textEntry. We had to modify this line of code:

        JTextField textEntry = new JTextField(INITIAL_TEXT, 30);
to be:
        textEntry = new JTextField(INITIAL_TEXT, 30);
In the original version, we introduce a local variable that shadows the field. This is a common bug that you might encounter.

Then we added two new text fields to the southern panel for storing the x and y coordinates to use for drawing the String. The old version of the code used 50 for both x and y. We introduced a new constant for this:

        private static final int INITIAL_XY = 50;
Then we wrote some code to add two new text fields. I pointed out that there are several ways to convert an int to a String including the static methods Integer.toString and String.valueOf, but this is a case where the common Java idiom is to append to an empty string:

        JTextField xEntry = new JTextField("" + INITIAL_XY, 3);
        JTextField yEntry = new JTextField("" + INITIAL_XY, 3);
Then we turned to the question of what action listener to attach to these. You could imagine each one having its own action listener and having different update methods that update just the text or just the x-coordinate or just the y-coordinate, but this is a case where it makes more sense to put these all together into one kind of update (updating the text parameters). So we'll have just one method called updatePanel that will be called by all three text fields. We could attach three copies of the same listener:

            textEntry.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    updatePanel();
                }
            });
            xEntry.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    updatePanel();
                }
            });
            yEntry.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    updatePanel();
                }
            });
That would be very redundant. Instead, we can pull the code for constructing the ActionListener out of the call on setActionListener and then attach the same listener to all three. This leads to us having a local variable of type ActionListener:

        ActionListener textFieldListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                updatePanel();
            }
        };
        textEntry.addActionListener(textFieldListener);
        xEntry.addActionListener(textFieldListener);
        yEntry.addActionListener(textFieldListener);
I briefly outlined what was left to do, but I won't repeat that here given that we did it more slowly in Wednesday's lecture.


Stuart Reges
Last modified: Fri Apr 20 10:18:40 PDT 2007