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); } }