Multi-View Applications

A multi-view application allows users to create multiple views of a single model. This is useful if there are different types of view (e.g., normal, print layout, outline) or different views show different show different parts of a large model (e.g., the top and bottom of a long document.)

Naturally, using a view to change the model automatically updates all of the other views.

Example

Using our lame spreadsheet from the previous lecture, we will create an application that allows multiple views of a table model. A Document menu allows users to create new views. In this screenshot two views of a table model are open:

Design

The design is similar to the design of the Table example, except TableFrame extends JInternalFrame:

ClassDiagram1

The role of desktop window is played by ParentAppFrame, which can add multiple TableFrames to its JDesktopPane:

ClassDiagram1

Implementation

The complete implementation is in ParentAppFrame.java.

Imports

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;

Internal Frames

class TableFrame extends JInternalFrame {
   private static int openFrameCount = 0;
   public TableFrame(TableCalculator model) {
        super("Document #" + (++openFrameCount),
              true, //resizable
              true, //closable
              true, //maximizable
              true);//iconifiable
        TablePanel view = new TablePanel(model);
        setContentPane(view);
        pack();
   }
}

The Desktop Pane and Parent Frame

public class ParentAppFrame extends JFrame implements ActionListener {

   private static final long serialVersionUID = 1L;
   private JDesktopPane desktop;
   private TableCalculator model;

   public ParentAppFrame() {
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setDefaultLookAndFeelDecorated(true);
      desktop = new JDesktopPane(); //a specialized layered pane
      model = new TableCalculator();
      createFrame(); //create first "window"
      setContentPane(desktop);
      setJMenuBar(createMenuBar());

      //Make dragging a little faster but perhaps uglier.
      desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
   }

   public void actionPerformed(ActionEvent e) {
        if ("new".equals(e.getActionCommand())) { //new
            createFrame();
        } else { //quit
            System.exit(1);
        }
    }

    //Create a new internal frame.
    protected void createFrame() {
        TableFrame frame = new TableFrame(model);
        frame.setVisible(true); //necessary as of 1.3
        desktop.add(frame);

        try {
            frame.setSelected(true);
        } catch (java.beans.PropertyVetoException e) {}

    }

    protected JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();

        //Set up the lone menu.
        JMenu menu = new JMenu("Document");
       
menu.setMnemonic(KeyEvent.VK_D);
        menuBar.add(menu);

        //Set up the first menu item.
        JMenuItem menuItem = new JMenuItem("New");
        menuItem.setMnemonic(KeyEvent.VK_N);
        menuItem.setAccelerator(KeyStroke.getKeyStroke(
                KeyEvent.VK_N, ActionEvent.ALT_MASK));
        menuItem.setActionCommand("new");
        menuItem.addActionListener(this);
        menu.add(menuItem);

        //Set up the second menu item.
        menuItem = new JMenuItem("Quit");
        menuItem.setMnemonic(KeyEvent.VK_Q);
        menuItem.setAccelerator(KeyStroke.getKeyStroke(
                KeyEvent.VK_Q, ActionEvent.ALT_MASK));
        menuItem.setActionCommand("quit");
        menuItem.addActionListener(this);
        menu.add(menuItem);

        return menuBar;
    }

   public static void main(String[] args) {
      ParentAppFrame frame = new ParentAppFrame();
      frame.setSize(300, 400);
      frame.setTitle("App Frame");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}