|
GUI Layout Using the M-V-C Pattern
A Discussion with Examples in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
JContainerModel interfaceJContainerView interfaceimport java.awt.*;
import javax.swing.*;
/**
* The requirements of a container that uses the MVC pattern
* for layout.
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public interface JContainerModel
{
/**
* Gets a component in this container.
*
* @param name The name of the component
* @return The component (or null)
*/
public abstract JComponent getComponentNamed(String name);
/**
* Set the view associated with this container
*
* @param view The view
*/
public abstract void setJContainerView(JContainerView view);
// These methods are implement by Container objects
// and are included as part of this interface for
// convenience
public abstract Component add(Component comp);
public abstract Component add(Component comp, int index);
public abstract void add(Component comp, Object constraints);
public abstract Component add(String name, Component comp);
public abstract Color getBackground();
public abstract void setFont(Font f);
public abstract void setLayout(LayoutManager mgr);
}
/**
* The requirements of the view for a container that uses the MVC pattern
* for layout.
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public interface JContainerView
{
/**
* Set the text for all of the tool tips
*/
public abstract void setToolTipText();
/**
* Setup this view (Required by JContainerView)
*/
public abstract void setupView();
}
constructComponents() and
areComponentsConstructed() methods in the model
and let either the model or the view construct the components
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* A component used to edit a JList containing Strings.
*
* @version 2.0 (Uses the MVC Pattern)
* @author Prof. David Bernstein, James Madison University
*/
public class JListEditor extends JPanel
implements ActionListener, DocumentListener,
ListSelectionListener, JContainerModel
{
private static final long serialVersionUID = 1L;
private static final String DEFAULT_TITLE = "Current Entries:";
protected DefaultListModel<String> lines;
protected HashMap<String, JComponent> components;
protected JButton deleteButton, addButton;
protected JLabel titleLabel;
protected JList<String> list;
protected JContainerView view;
protected JTextField valueField;
protected String title;
/**
* Construct a new JListEditor that displays
* the elements in the specified non-null model.
*
* @param dataModel The (non-null) model to use
*
*/
public JListEditor(ListModel<String> dataModel)
{
super();
list = new JList<String>(dataModel);
lines = (DefaultListModel<String>)dataModel;
constructComponents();
}
/**
* Construct a new JListEditor that displays
* the elements in the specified array.
*
* @param listData The array of elements to use
*
*/
public JListEditor(String[] listData)
{
super();
list = new JList<String>(listData);
lines = (DefaultListModel<String>)list.getModel();
constructComponents();
}
/**
* Construct a new JListEditor with an empty model.
*/
public JListEditor()
{
super();
lines = new DefaultListModel<String>();
list = new JList<String>(lines);
constructComponents();
}
/**
* Handle actionPerformed messages.
*
* @param e The ActionEvent that generated the message.
*/
public void actionPerformed(ActionEvent e)
{
String ac = e.getActionCommand();
if (ac.equals("add_JListEditor")) handleAdd();
else if (ac.equals("delete_JListEditor")) handleDelete();
}
/**
* Add a ListSelectionListener.
*
* @param listener The ListSelectionListener to add
*/
public void addListSelectionListener(ListSelectionListener listener)
{
list.addListSelectionListener(listener);
}
/**
* Add a new line.
*
* @param value The value to add
*/
private void addLine(String value)
{
lines.addElement(value);
}
/**
* Handle changedUpdate messages.
*
* @param evt The DocuementEvent that generated the message
*/
public void changedUpdate(DocumentEvent evt)
{
// Do nothing
}
/**
* Check to see if all of the fields are filled-in.
*/
public void checkFields()
{
if (!valueField.getText().equals(""))
{
addButton.setEnabled(true);
deleteButton.setEnabled(false);
}
}
/**
* Construct the components used by this JListEditor
*/
protected void constructComponents()
{
components = new HashMap<String, JComponent>();
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addListSelectionListener(this);
components.put("list", list);
valueField = new JTextField();
valueField.getDocument().addDocumentListener(this);
components.put("valueField", valueField);
addButton = new JButton("Add");
addButton.setEnabled(false);
addButton.setActionCommand("add_JListEditor");
addButton.addActionListener(this);
components.put("addButton", addButton);
deleteButton = new JButton("Delete");
deleteButton.setEnabled(false);
deleteButton.setActionCommand("delete_JListEditor");
deleteButton.addActionListener(this);
components.put("deleteButton", deleteButton);
title = DEFAULT_TITLE;
titleLabel = new JLabel(title, JLabel.LEFT);
components.put("title", titleLabel);
checkFields();
// Set the view
//setJContainerView(new JListEditorTraditionalView(this));
setJContainerView(new JListEditorModernView(this));
}
/**
* Gets a component in this container.
*
* @param name The name of the component
* @return The component (or null)
*/
public JComponent getComponentNamed(String name)
{
return (JComponent)components.get(name);
}
/**
* Returns the data model that holds the list
* of items displayed by the JList component.
*
* @return The ListModel that provides the list of items
*/
public ListModel<String> getModel()
{
return list.getModel();
}
/**
* Returns the index of the currently selected
* item in the list.
*
* @return The index of the currently selected item
*/
public int getSelectedIndex()
{
return list.getSelectedIndex();
}
/**
* Returns the indices of the currently selected items.
*
* @return The indices of the currently selected items
*/
public int[] getSelectedIndices()
{
return list.getSelectedIndices();
}
/**
* Returns the currently selected item in the list.
*
* @return The currently selected item
*/
public Object getSelectedValue()
{
return list.getSelectedValue();
}
/**
* Return and array containing the currently selected items.
*
* @return The currently selected items
*/
public java.util.List<String> getSelectedValuesList()
{
return list.getSelectedValuesList();
}
/**
* Handle the Delete button.
*/
private void handleDelete()
{
int i = list.getSelectedIndex();
if (i >= 0)
{
lines.removeElementAt(i);
deleteButton.setEnabled(false);
addButton.setEnabled(false);
valueField.setText("");
}
}
/**
* Handle the Add button.
*/
private void handleAdd()
{
String value = valueField.getText();
if ( !value.equals(""))
{
for (int i=0; i < lines.size(); i++)
{
String s = (String)lines.elementAt(i);
if (s.equals(value) ) {
lines.removeElementAt(i);
break; // Out of the for loop
}
}
addLine(value);
addButton.setEnabled(false);
list.setSelectedIndex(lines.size()-1);
}
valueField.setText("");
}
/**
* Handle insertUpdate messages.
*
* @param evt The DocumentEvent that generated the message
*/
public void insertUpdate(DocumentEvent evt)
{
// Regardless of which field/document generated the event
checkFields();
}
/**
* Handle removeUpdate messages.
*
* @param evt The DocumentEvent that generated the message
*/
public void removeUpdate(DocumentEvent evt)
{
// Regardless of which field/document generated the event
checkFields();
}
/**
* Sets the background color for this JListEditor.
*
* @param c The Color to use
*/
public void setBackground(Color c)
{
Component[] comps;
int i;
super.setBackground(c);
comps = getComponents();
for (i=0; i < comps.length; i++)
{
comps[i].setBackground(c);
}
}
/**
* Set the view associated with this container.
*
* @param view The view
*/
public void setJContainerView(JContainerView view)
{
this.view = view;
view.setupView();
view.setToolTipText();
invalidate();
validate();
}
/**
* Set the title of this JListEditor.
*
* @param title The new title
*/
public void setTitle(String title)
{
this.title = title;
titleLabel.setText(title);
}
/**
* Handle valueChanged messages.
*
* @param lse The ListSelectionEvent that generated the message
*/
public void valueChanged(ListSelectionEvent lse)
{
int i = list.getSelectedIndex();
if (i >= 0)
{
String s = (String)list.getSelectedValue();
valueField.setText(s);
checkFields();
addButton.setEnabled(false);
deleteButton.setEnabled(true);
}
else
{
deleteButton.setEnabled(false);
}
}
}
import javax.swing.*;
/**
* An abstract "view" for a JListEditor.
*
* @version 2.0 (Uses the MVC Pattern)
* @author Prof. David Bernstein, James Madison University
*/
public abstract class JListEditorView implements JContainerView
{
protected JContainerModel container;
/**
* Explicit Value Constructor.
*
* @param jle The JListEditor (i.e., the JContainerModel)
*/
public JListEditorView(JListEditor jle)
{
this.container = jle;
}
/**
* Set the text for all of the tool tips.
*/
public void setToolTipText()
{
setToolTipText("list", "The current list of items.");
setToolTipText("valueField", "Enter a new item here.");
setToolTipText("addButton", "Add the new item.");
setToolTipText("deleteButton", "Delete the selected entry.");
}
/**
* Set the tool tip text for a particular component.
*
* @param name The name of the component
* @param text The text of the tool tip
*/
protected void setToolTipText(String name, String text)
{
JComponent c;
c = container.getComponentNamed(name);
if (c != null) c.setToolTipText(text);
}
/**
* Setup this view (Required by JContainerView)
*/
public abstract void setupView();
}
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
/**
* A traditional "view" for a JListEditor.
*
* @version 2.0 (Uses the MVC Pattern)
* @author Prof. David Bernstein, James Madison University
*/
public class JListEditorTraditionalView extends JListEditorView
{
/**
* Explicit Value Constructor
*
* @param jle The JListEditor (i.e., the JContainerModel)
*/
public JListEditorTraditionalView(JListEditor jle)
{
super(jle);
}
/**
* Setup this view (Required by JContainerView)
*/
public void setupView()
{
JComponent c;
JPanel center, south, s1, s2;
JScrollPane listPane;
container.setFont(new Font("Sans Serif",Font.PLAIN,12));
container.setLayout(new BorderLayout());
c = container.getComponentNamed("titleLabel");
if (c != null) container.add(c, BorderLayout.NORTH);
c = container.getComponentNamed("list");
if (c != null)
{
center = new JPanel();
center.setLayout(new BorderLayout());
center.setBorder(BorderFactory.createBevelBorder(
BevelBorder.LOWERED));
listPane = new JScrollPane(c);
center.add(listPane, BorderLayout.CENTER);
container.add(center, BorderLayout.CENTER);
}
south = new JPanel();
south.setLayout(
new BoxLayout(south, BoxLayout.Y_AXIS));
south.setBorder(
BorderFactory.createMatteBorder(6,6,6,6,
container.getBackground()));
s1 = new JPanel();
s1.setLayout(new BorderLayout());
c = container.getComponentNamed("valueField");
if (c!= null) s1.add(c);
s2 = new JPanel();
s2.setLayout(new BoxLayout(s2, BoxLayout.X_AXIS));
s2.add(Box.createHorizontalGlue());
c = container.getComponentNamed("addButton");
if (c != null) s2.add(c);
c = container.getComponentNamed("deleteButton");
if (c != null) s2.add(c);
south.add(Box.createVerticalStrut(10));
south.add(s1);
south.add(Box.createVerticalStrut(5));
south.add(s2);
south.add(Box.createVerticalStrut(10));
container.add(south, BorderLayout.SOUTH);
container.add(new JLabel(" "), BorderLayout.EAST);
container.add(new JLabel(" "), BorderLayout.WEST);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
/**
* A modern "view" for a JListEditor.
*
* @version 2.0 (Uses the MVC Pattern)
* @author Prof. David Bernstein, James Madison University
*/
public class JListEditorModernView extends JListEditorView
{
/**
* Explicit Value Constructor.
*
* @param jle The JListEditor (i.e., the JContainerModel)
*/
public JListEditorModernView(JListEditor jle)
{
super(jle);
}
/**
* Setup this view.
*/
public void setupView()
{
JComponent c;
JPanel center, north, n1, n2, south, s1;
JScrollPane listPane;
container.setFont(new Font("Sans Serif",Font.PLAIN,12));
container.setLayout(new BorderLayout());
c = container.getComponentNamed("titleLabel");
if (c != null) container.add(c, BorderLayout.NORTH);
c = container.getComponentNamed("list");
if (c != null)
{
center = new JPanel();
center.setLayout(new BorderLayout());
center.setBorder(BorderFactory.createBevelBorder(
BevelBorder.LOWERED));
listPane = new JScrollPane(c);
center.add(listPane, BorderLayout.CENTER);
container.add(center, BorderLayout.CENTER);
}
south = new JPanel();
south.setLayout(
new BoxLayout(south, BoxLayout.Y_AXIS));
south.setBorder(
BorderFactory.createMatteBorder(6,6,6,6,
container.getBackground()));
s1 = new JPanel();
s1.setLayout(new BoxLayout(s1, BoxLayout.X_AXIS));
s1.add(Box.createHorizontalGlue());
c = container.getComponentNamed("deleteButton");
if (c != null) s1.add(c);
south.add(Box.createVerticalStrut(10));
south.add(s1);
south.add(Box.createVerticalStrut(10));
north = new JPanel();
north.setLayout(
new BoxLayout(north, BoxLayout.Y_AXIS));
north.setBorder(
BorderFactory.createMatteBorder(6,6,6,6,
container.getBackground()));
n1 = new JPanel();
n1.setLayout(new BorderLayout());
c = container.getComponentNamed("valueField");
if (c!= null) n1.add(c, BorderLayout.CENTER);
n2 = new JPanel();
n2.setLayout(new BoxLayout(n2, BoxLayout.X_AXIS));
n2.add(Box.createHorizontalGlue());
c = container.getComponentNamed("addButton");
if (c != null) n2.add(c);
north.add(Box.createVerticalStrut(10));
north.add(n1);
north.add(Box.createVerticalStrut(5));
north.add(n2);
north.add(Box.createVerticalStrut(10));
container.add(north, BorderLayout.NORTH);
container.add(south, BorderLayout.SOUTH);
container.add(new JLabel(" "), BorderLayout.EAST);
container.add(new JLabel(" "), BorderLayout.WEST);
}
}