MVC Implementation
/* * Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Point2D; import java.io.IOException; import java.util.ArrayList; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * MVC Implementation * * @author Ian Darwin, http://www.darwinsys.com/ * @version $Id: MVCDemo.java,v 1.3 2004/03/21 00:44:36 ian Exp $ */ public class MVCDemo { /** "main program" method - construct and show */ public static void main(String[] av) { // Create the data model final Model model = new Model(); // create a JFrame to hold it all. final JFrame f = new JFrame("MVC"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container cp = f.getContentPane(); JPanel tp = new JPanel(); cp.add(tp, BorderLayout.NORTH); tp.add(new JLabel("New value:")); final JTextField tf = new JTextField(10); tp.add(tf); tf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { model.add(tf.getText()); tf.setText(""); } }); JPanel p = new JPanel(); // The first View is a JTextArea subclassed to have // an easy way of setting the data from a java.util.List final TextView tv = new TextView(); model.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { Object o = evt.getSource(); Model m = (Model) o; tv.setListData(m.getData()); } }); tv.setBackground(Color.RED); tv.setSize(100, 100); p.add(tv); // The second View is the simplistic Grapher program from // the Java Cookbook "Graphics" chapter (../graphics/Grapher.java) final Grapher vv = new Grapher(); model.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { Object o = evt.getSource(); Model m = (Model) o; vv.setListData(m.getData()); } }); vv.setBackground(Color.YELLOW); vv.setSize(100, 100); p.add(vv); cp.add(p, BorderLayout.CENTER); f.pack(); f.setLocation(100, 100); f.setVisible(true); } } class TextView extends JTextArea { public TextView() { super(20, 20); } public void setListData(ArrayList l) { setText(""); for (int i = 0; i < l.size(); i++) { append((String) l.get(i)); append("\n"); } } } class Model { private ArrayList list = new ArrayList(); public void add(String s) { list.add(s); fireChange(); } public ArrayList getData() { return list; } // Sun recommends using javax.swing.EventListenerList, but this is easier ArrayList changeListeners = new ArrayList(); public void addChangeListener(ChangeListener cl) { changeListeners.add(cl); } public void removeChangeListener(ChangeListener cl) { changeListeners.remove(cl); } protected void fireChange() { ChangeEvent evt = new ChangeEvent(this); for (int i = 0; i < changeListeners.size(); i++) { ChangeListener cl = (ChangeListener) changeListeners.get(i); cl.stateChanged(evt); } } } class Grapher extends JPanel { /** Multiplier for range to allow room for a border */ public final static double BORDERFACTOR = 1.1f; /** The list of Point points. */ protected ArrayList data; /** The minimum and maximum X values */ protected double minx = Integer.MAX_VALUE, maxx = Integer.MIN_VALUE; /** The minimum and maximum Y values */ protected double miny = Integer.MAX_VALUE, maxy = Integer.MIN_VALUE; /** The range of X and Y values */ protected double xrange, yrange; public Grapher() { data = new ArrayList(); figure(); } /** * Set the list data from a list of Strings, where the x coordinate is * incremented automatically, and the y coordinate is made from the String * in the list. */ public void setListDataFromYStrings(ArrayList newData) { data.clear(); for (int i = 0; i < newData.size(); i++) { Point2D p = new Point2D.Double(); p.setLocation(i, java.lang.Double.parseDouble((String) newData .get(i))); data.add(p); } figure(); } /** Set the list from an existing List, as from GraphReader.read() */ public void setListData(ArrayList newData) { data = newData; figure(); } /** Compute new data when list changes */ private void figure() { // find min & max for (int i = 0; i < data.size(); i++) { Point2D d = (Point2D) data.get(i); if (d.getX() < minx) minx = d.getX(); if (d.getX() > maxx) maxx = d.getX(); if (d.getY() < miny) miny = d.getY(); if (d.getY() > maxy) maxy = d.getY(); } // Compute ranges xrange = (maxx - minx) * BORDERFACTOR; yrange = (maxy - miny) * BORDERFACTOR; } /** * Called when the window needs painting. Computes X and Y range, scales. */ public void paintComponent(Graphics g) { super.paintComponent(g); Dimension s = getSize(); if (data.size() < 2) { g.drawString("Insufficient data: " + data.size(), 10, 40); return; } // Compute scale factors double xfact = s.width / xrange; double yfact = s.height / yrange; // Scale and plot the data for (int i = 0; i < data.size(); i++) { Point2D d = (Point2D) data.get(i); double x = (d.getX() - minx) * xfact; double y = (d.getY() - miny) * yfact; // Draw a 5-pixel rectangle centered, so -2 both x and y. // AWT numbers Y from 0 down, so invert: g.drawRect(((int) x) - 2, s.height - 2 - (int) y, 5, 5); } } public Dimension getPreferredSize() { return new Dimension(150, 150); } public static void main(String[] args) throws IOException { final JFrame f = new JFrame("Grapher"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Grapher grapher = new Grapher(); f.setContentPane(grapher); f.setLocation(100, 100); f.pack(); ArrayList data = new ArrayList(); data.add("a"); grapher.setListData(data); f.setVisible(true); } }
1. | MVC Pattern in Java 2 | ||
2. | MVC Loop |