JMU
The Model-View-Controller Pattern
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Motivation
A Model of the M-V-C Pattern
images/mvc_pattern.gif
An Example: MVCTextField
images/MVCTextField_context.gif
An Example: MVCTextField (cont.)

Handling an arrowkeyPressed Event

images/MVCTextField_arrowkeyPressed.gif
An Example: MVCTextField (cont.)

Handling a mouseUp Event

images/MVCTextField_mouseUp.gif
An Example: MVCTextField (cont.)

Handling a characterKeyPressed Event

images/MVCTextField_characterkeyPressed.gif
An Example: An IntegerEntryField
Benefits of the M-V-C Pattern

Creating an IntegerDocument

javaexamples/mvc/IntegerDocument.java
        package mvc;

import javax.swing.text.*;

/**
 * A Document that can only contain integer values
 *
 * Note: In order to be simple and clear, this implementation
 * does not support numbers with a leading '+' and will not allow
 * the document to contain only a '-'.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class IntegerDocument extends PlainDocument
{

    /**
     * Check to see if an insertString() will result in an Integer or
     * not.
     *
     * @param  offset  The starting offset
     * @param  text    The string to insert
     * @return         true if OK; false otherwise
     */
    public boolean checkInsert(int offset, String text)
    {
       boolean      result;       
       String       newText;
       
       try 
       {
          newText = super.getText(0, offset) + text + 
             super.getText(offset, getLength()-offset);

          Integer.parseInt(newText);
          result = true;
       }
       catch (Exception e)
       {
          result = false;
       }

       return result;       
    }

    /**
     * Check to see if a remove() will result in an Integer or not.
     *
     * @param  offset  The starting offset
     * @param  length  The length to remove
     * @return         true if OK; false otherwise
     */
    public boolean checkRemove(int offset, int remove)
    {
       boolean      result;       
       String       newText;
       
       try 
       {
          newText = super.getText(0, offset) + 
             super.getText(offset+remove, getLength()-offset-remove);

          if (!newText.equals("")) Integer.parseInt(newText);
          result = true;
       }
       catch (Exception e)
       {
          result = false;
       }

       return result;       
    }
    

    /**
     * Check to see if a replace() will result in an Integer or
     * not.
     *
     * @param  offset  The starting offset
     * @param  length  The length to remove
     * @param  text    The string to insert
     * @return         true if OK; false otherwise
     */
    public boolean checkReplace(int offset, int remove, String text)
    {
       boolean      result;       
       String       newText;
       
       try 
       {
          newText = super.getText(0, offset) + text + 
             super.getText(offset+remove, getLength()-offset-remove);

          if (!newText.equals("")) Integer.parseInt(newText);
          result = true;
       }
       catch (Exception e)
       {
          result = false;
       }

       return result;       
    }
    

    /**
     * Inserts content into the document (but only if 
     * the result is an Integer)
     *
     * @param offset   The starting offset
     * @param text     The string to insert
     * @param a        The attributes for the inserted text
     */
    public void insertString(int offset, String text, AttributeSet a) 
                throws BadLocationException
    {
       if (checkInsert(offset, text)) super.insertString(offset, text, a);
    }

    /*
     * Remove some content from the document (but only if the result is
     * a SimpleTime).
     *
     * @param offset The starting offset
     * @param length The number of characters to remove 
     */
    public void remove(int offset, int length) 
                throws BadLocationException
    {
       if (checkRemove(offset, length)) super.remove(offset, length);
    }


    /**
     * Deletes the region of text from offset to offset + length, and
     * replaces it with text.
     *
     * @param offset The starting offset
     * @param length The number of characters to remove 
     * @param text   The string to insert
     * @param a      The attributes for the inserted text
     */
    public void replace(int offset, int length, String text, AttributeSet a)  
                throws BadLocationException
    {
       if (checkReplace(offset, length, text)) 
          super.replace(offset, length, text, a);
    }
}
        
Benefits of the M-V-C Pattern (cont.)

Creating an IntegerEntryField

javaexamples/mvc/IntegerEntryField.java
        package mvc;

import javax.swing.*;
import javax.swing.text.*;

/**
 * An entry field that only accepts integers
 *
 * Note: In order to be simple and clear, this implementation
 * does not support numbers with a leading '+' and will not allow
 * the document to contain only a '-'.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0 
 */
public class IntegerEntryField extends JTextField
{
    /**
     * Create a Document (i.e., model) for this IntegerEntryField
     *
     * @return  An IntegerDocument
     */
    protected Document createDefaultModel()
    {
        return new IntegerDocument();
    }
}
        
Benefits of the M-V-C Pattern (cont.)
Benefits of the M-V-C Pattern (cont.)

Skins/PLAF

javaexamples/lookandfeel/PLAFdemo.java
        package lookandfeel;


import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;

import gui.*;

/**
 * An example that illustrates the use of the 
 * pluggable look-and-feel feature
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class PLAFdemo
{

    /**
     * The entry point
     */
    public static void main(String[] args)
    {
        BufferedReader   in;
        CloseableFrame               f;
        Container                    contentPane;
        int                          i;
        JListEditor                  jle;
        String                       choice, systemPLAF;
        UIManager.LookAndFeelInfo[]  info;


        f = new CloseableFrame();

        contentPane = f.getContentPane();
        contentPane.setLayout(new BorderLayout());

        jle = new JListEditor();
        contentPane.add(jle, BorderLayout.CENTER);


        f.setSize(400,300);
        f.setVisible(true);

        // To use the system look and feel
        //try 
        //{
        //   lookAndFeel = UIManager.getSystemLookAndFeelClassName();
        //   UIManager.setLookAndFeel(lookAndFeel);
        //}
        //catch (Exception e)
        //{
        //   // Use the default look and feel
        //}
        


        // Add two new views
        // Note: The .jar files need to be in the classpath
        try {

            UIManager.setLookAndFeel(new com.incors.plaf.kunststoff.KunststoffLookAndFeel());

            UIManager.setLookAndFeel(new net.sourceforge.mlf.metouia.MetouiaLookAndFeel());



        } catch (Exception e) {

            e.printStackTrace();
        }


        // Get all of the views
        info = UIManager.getInstalledLookAndFeels();



        // Print the views
        info = UIManager.getInstalledLookAndFeels();

        for (i=0; i < info.length; i++) {

            System.out.println(i+"\t"+info[i].getClassName());
        }
        
            
        // Allow the user to change the views
        in = new BufferedReader(new InputStreamReader(System.in));
        while (true) {

            try {

                System.out.print("Number? ");
                choice = in.readLine();

                i = Integer.parseInt(choice);

                UIManager.setLookAndFeel(info[i].getClassName());

                SwingUtilities.updateComponentTreeUI(f);
                //f.pack();


            } catch (NumberFormatException nfe) {

                System.exit(9);

            } catch (IOException ioe) {

                // Ignore

            } catch (ClassNotFoundException cnfe) {

                System.out.println("Couldn't set look and feel");

            } catch (InstantiationException ie) {

                System.out.println("Couldn't set look and feel");

            } catch (IllegalAccessException ie) {

                System.out.println("Couldn't set look and feel");

            } catch (UnsupportedLookAndFeelException ie) {

                System.out.println("Couldn't set look and feel");
            }
        }


    }




}