User Interface Pane

The user interface pane is the container for the graphical widgets. Besides the input fields we will have buttons and a table. From the main scenario we already see what responsibilities the user interface panel will have. At the beginning it should be possible to initialize it for the given frame. We do the initialization more generally, since we want to reuse the user interface panel for the applet component. Therefore we define an initPane() method as follows:

    /**
     * <p>After the knowledge base is loaded or a query
* has been processed we use the following layout with
* the buttons enabled:</p>
     * <pre>
     *       Firstname: [          ]
     *       Name:      [          ]
     *       Age:       From [   ] To [   ]
     *       Salary:    From [     ] To [     ]
     *                           [ Debug ] [ Search ]
     *       +-------------- Results ---------------+
     *       |                                      |
     *       |                                      |
     *       +--------------------------------------+
     * <pre>
     *
     * @param r The root pane.
     * @param s The  action listener.
     */
    void initPane(JRootPane r, ActionListener s) {

Inside the init method first the input fields are placed on the plane. String input fields are left adjusted, whereas number input fields are right adjusted. For the number search criteria two number input fields are necessary, one for the “from” value and one for the “to” value. Here is an excerpt seen that initializes the name search criteria and part of the age search criteria:

        c.add(new JLabel("Name:"), new GridBagConstraints(0, 1, 
                1, 1, 0.0, 0.0
                , GridBagConstraints.WEST,
                GridBagConstraints.NONE,
                new Insets(2, 2, 2, 2), 0, 0));
        c.add(name, new GridBagConstraints(1, 1,
                4, 1, 0.0, 0.0
                , GridBagConstraints.WEST,
                GridBagConstraints.NONE,
                new Insets(2, 2, 2, 2), 0, 0));
        c.add(new JLabel("Age:"), new GridBagConstraints(0, 2,
                1, 1, 0.0, 0.0
                , GridBagConstraints.WEST,
                GridBagConstraints.NONE,
                new Insets(2, 2, 2, 2), 0, 0));
        c.add(new JLabel("From"), new GridBagConstraints(1, 2,
                1, 1, 0.0, 0.0
                , GridBagConstraints.WEST,
                GridBagConstraints.NONE,
                new Insets(2, 2, 2, 2), 0, 0));
        ageFrom.setHorizontalAlignment(SwingConstants.RIGHT);
        c.add(ageFrom, new GridBagConstraints(2, 2,
                1, 1, 0.0, 0.0
                , GridBagConstraints.WEST,
                GridBagConstraints.NONE,
                new Insets(2, 2, 2, 2), 0, 0));

For the buttons we use a sub-panel so that we can place the buttons close together and right adjusted to the surrounding container. The buttons will register themselves on the action listener provided to the initialization method. Because we have two buttons, we will give them different action command strings. This way the action listener can easily detect which button was pressed. The code reads as follows:

        /* layout the action buttons */
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());
        JButton debug = new JButton("Debug");
        debug.setActionCommand("debug");
        debug.addActionListener(s);
        panel.add(debug);
        JButton search = new JButton("Search");
        search.setActionCommand("search");
        r.setDefaultButton(search);
        search.addActionListener(s);
        panel.add(search);
        c.add(panel, new GridBagConstraints(0, 4,
                5, 1, 0.0, 0.0
                , GridBagConstraints.EAST,
                GridBagConstraints.NONE,
                new Insets(2, 2, 2, 2), 0, 0));

The initialization method also contains code to place the table. The details can be found in the appendix. The next responsibility of the user interface pane is the access to the search criteria. String values and number values are returned as strings, so that blank values can also be represented. For number search criteria there are two accessors, one for the “from” value and one for the “to” value. Here is an excerpt seen that allows accessing the name search criteria and part of the age search criteria:

    /**
     * <p>Retrieve the name.
     *
     * @return The name.
     */
    String getName() {
        return name.getText();
    }

    /**
     * <p>Retrieve the age from.
     *
     * @return The age from.
     */
    String getAgeFrom() {
        return ageFrom.getText();
    }

We now turn to the last responsibility of the user interface pane. Namely the user interface panel should be able to show the query results in a table. We have opted for a solution where the query results also carries information of the available columns. So the query result can come with varying number of columns depending on the query. Although in the current example we do not make use of this possibility. The update of the columns and the table reads as follows:

    /**
     * <p>Set the result.</p>
     *
     * @param colids The column identifiers.
     * @param rows   The rows.
     */
    void setResult(String[] colids, Object[][] rows) {
        /* reset all rows and set the columns */
        ((DefaultTableModel) result.getModel()).setDataVector(null,
                colids);
        DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)
                result.getDefaultRenderer(BigInteger.class);
        renderer.setHorizontalAlignment(SwingConstants.RIGHT);
        for (int i = 0; i < colids.length; i++)
            if (colids[i].endsWith("#"))
                result.getColumnModel().getColumn(
                        i).setCellRenderer(renderer);

        /* set the rows */
        for (int i = 0; i < rows.length; i++)
            ((DefaultTableModel) result.getModel()).addRow(rows[i]);
    }

The table itself uses a default column model and a default table model. These models are powerful enough for the dynamic configuration we have in mind. The update of the column model not only sets all the column names. It also right adjusts number columns by updating the corresponding cell renderer. Since the table is not editable, updating the cell renderer is enough. Otherwise we would need to update the cell editor as well.

Kommentare