CSE190L Notes for Friday, 4/13/07

We spent more time exploring layout managers and how they operate. Much of this material is in chapter 9 of the text, so I won't try to reproduce it here, but I'll summarize some of the issues we discussed and the code that we wrote.

We continued to use the same program to explore some of these issues. We explored a third kind of layout manager called GridLayout. As its name implies a GridLayout divides a JPanel into a rectangular grid of cells. The cells will all be exactly the same size. We modified the code for the panel of buttons to use a GridLayout:

        private JPanel buttonPanel() {
            JPanel result = new JPanel();
            result.setLayout(new GridLayout(2, 3));
            result.add(makeButton("Yellow", Color.YELLOW), BorderLayout.NORTH);
            result.add(makeButton("Blue", Color.BLUE), BorderLayout.SOUTH);
            result.add(makeButton("Red", Color.RED), BorderLayout.EAST);
            result.add(makeButton("Magenta", Color.MAGENTA), BorderLayout.WEST);
            result.add(makeButton("Green", Color.GREEN), BorderLayout.CENTER);
            return result;
        }
This version requests a GridLayout with 2 rows and 3 columns. The calls on add still pass a second parameter left over from when we were using a BorderLayout. In terms of style it would be best to delete these, but in practice these don't cause a problem because the GridLayout ignores this second parameter.

We tried various settings and found the odd fact (documented in the Java api documentation) that the GridLayout ignores the number of columns unless you set the number of rows to 0.

I also spent some time discussing the use of the pack method. We've been looking at programs that set the outer frame to a particular size. Another approach is to add all of the elements to the frame and then to call:

        frame.pack();
This instructs Java to talk to all of the layout managers and to layout the various components so that they each get their preferred size. It would be more precise to say that everything gets at least its preferred size because we know that sometimes a component is stretched a bit (as in north/south components in a BorderLayout that might be given more width than they prefer).

Horstmann doesn't seem to use pack very much, but it is a very useful method that many Java programmers use. Of course, to make it work properly, you have to make sure that your components have a preferred size. For example, we had to add this line of code to the ColorsPanel constructor:

        setPreferredSize(new Dimension(200, 200));
We tried making some calls on setSize and found that it doesn't work well. The Java philosophy is to have every component know about its preferred size and then to put in place a set of layout managers who together figure out how to layout the various components. If you make a call on setSize, you're basically fighting the layout manager and that's not a good idea.

Then I introduced the idea of a JTextField. This is a widget that will probably be familiar to most people. It allows a user to enter a short bit of text. I said that I wanted to modify our program to allow the user to enter the text that is being displayed in the colored panel. We introduced a constant for the initial version of this text:

        private static final String INITIAL_TEXT = "Hello World!";
and we modified the panel constructor to take this as a parameter. We had already switched the button panel to be in the north part of our frame and the colored panel to be in the center. So we started defining a new panel that would appear in the south. With the button panel we introduced a private method to construct the panel and I said we should do the same thing for the southern panel that will have the text fields. So our frame constructor now ended with these lines of code:

        frame.add(panel, BorderLayout.CENTER);
        frame.add(buttonPanel(), BorderLayout.NORTH);
        frame.add(textFieldPanel(), BorderLayout.SOUTH);
        frame.pack();
We then started working on the private method to construct the text field. We began with this:

        private JPanel textFieldPanel() {
            JPanel result = new JPanel();
            JTextField textEntry = new JTextField(INITIAL_TEXT, 30);
            result.add(textEntry);
            return result;
        }
In constructing the text field, you can pass a String to indicate the initial text and a number of columns to use. This column setting is somewhat bogus because Java does the calculation very badly. We saw that it left space for 40 or more characters. Still, it's best to use your best guess. This column setting will determine a width for the text field, but the user will be allowed to enter text that is longer than what can be displayed in the field.

This sort of worked. It caused a text field to appear in the lower part of the frame. But the user would find it fairly mysterious. What does this text field represent? Usually we include a label as well as a text field to include some information for the user about the purpose of the field:

        private JPanel textFieldPanel() {
            JPanel result = new JPanel();
            JTextField textEntry = new JTextField(INITIAL_TEXT, 30);
            result.add(new JLabel("text to display"));
            result.add(textEntry);
            return result;
        }
We found that the text field didn't really do anything. You have several options for making it do something. In the textbook, Horstmann shows how to attach a DocumentListener. In this case, I think a document listener is overkill. It wakes up every time there is any change at all to the text. Each individual character that the user types in the field will generate an event for the document listener to handle. In our case, I said that I wanted to attach an action listener. The action listener wakes up when the user hits the enter key inside the field. I said that we'd again use an anonymous inner class for the code:

        private JPanel textFieldPanel() {
            JPanel result = new JPanel();
            JTextField textEntry = new JTextField(INITIAL_TEXT, 30);
            textEntry.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // ...
                }
            });
            result.add(new JLabel("text to display"));
            result.add(textEntry);
            return result;
        }
but we didn't have time to work on the code, so I said we'd pick up here in Monday's lecture.


Stuart Reges
Last modified: Fri Apr 20 09:48:20 PDT 2007