这次的作业是做一个姓名使用趋势的展示作业,综合了很多知识,收获很大。

NameSurfer

/*
 * File: NameSurfer.java
 * ---------------------
 * When it is finished, this program will implements the viewer for
 * the baby-name database described in the assignment handout.
 */

import acm.program.*;
import java.awt.event.*;
import javax.swing.*;

public class NameSurfer extends Program implements NameSurferConstants {

/* Method: init() */
/**
 * This method has the responsibility for reading in the data base
 * and initializing the interactors at the top of the window.
 */
	public void init() {
	    // You fill this in, along with any helper methods //
		label=new JLabel("Name");
		text=new JTextField(20);
		graph=new JButton("Graph");
		clear=new JButton("Clear");
		deletion=new JButton("Deletion");
		add(label,NORTH);
		add(text,NORTH);
		add(graph,NORTH);
		add(clear,NORTH);
		add(deletion,NORTH);
		text.addActionListener(this);
		addActionListeners();
		
		//读取数据
		database=new NameSurferDataBase(NAMES_DATA_FILE);
		
		Graph = new NameSurferGraph();
		add(Graph);
		Graph.update();
		
	}

/* Method: actionPerformed(e) */
/**
 * This class is responsible for detecting when the buttons are
 * clicked, so you will have to define a method to respond to
 * button actions.
 */
	public void actionPerformed(ActionEvent e) {
		// You fill this in //
		if(e.getSource()==text) {
			String name=text.getText();
			NameSurferEntry entry=database.findEntry(name.toUpperCase());
			if(entry!=null) {
				Graph.addEntry(entry);
				Graph.update();
			}
			//println("Graph: \""+text.getText()+'"');
			//println("Graph: \""+database.findEntry(name.toUpperCase())+'"');
		}else if(e.getSource()==graph) {
			String name=text.getText();
			NameSurferEntry entry=database.findEntry(name.toUpperCase());
			if(entry!=null) {
				Graph.addEntry(entry);
				Graph.update();
			}
			//println("Graph: \""+text.getText()+'"');
			//println("Graph: \""+database.findEntry(name.toUpperCase())+'"');
		}else if(e.getSource()==clear){
			Graph.clear();
			Graph.update();
		}else {
			String name=text.getText();
			NameSurferEntry entry=database.findEntry(name.toUpperCase());
			Graph.deletion(entry);
			Graph.update();
		}
	}
	
	private JLabel label;
	private JTextField text;
	private JButton graph;
	private JButton clear;
	private JButton deletion;
	private NameSurferDataBase database;
	private NameSurferGraph Graph;
}

NameSurferDataBase

/*
 * File: NameSurferDataBase.java
 * -----------------------------
 * This class keeps track of the complete database of names.
 * The constructor reads in the database from a file, and
 * the only public method makes it possible to look up a
 * name and get back the corresponding NameSurferEntry.
 * Names are matched independent of case, so that "Eric"
 * and "ERIC" are the same names.
 */

import acm.util.*;
import java.io.*;
import java.util.*;

public class NameSurferDataBase implements NameSurferConstants {
	
/* Constructor: NameSurferDataBase(filename) */
/**
 * Creates a new NameSurferDataBase and initializes it using the
 * data in the specified file.  The constructor throws an error
 * exception if the requested file does not exist or if an error
 * occurs as the file is being read.
 */
	public NameSurferDataBase(String filename) {
		// You fill this in //
		
		database=new HashMap<String,NameSurferEntry>();
		
		//打开文件
		BufferedReader rd = null;
		try {
			rd=new BufferedReader(new FileReader(filename));
		}catch(IOException ex) {
			System.out.println("Can't open that file.");
		}
		
		//读取数据
		try {
			while(true) {
				String line=rd.readLine();
				if(line==null) {
					break;
				}
				NameSurferEntry text=new NameSurferEntry(line);
				database.put(text.getName().toUpperCase(), text);
			}
			rd.close();
		}catch(IOException ex) {
			throw new ErrorException(ex);
		}
		
	}
	
/* Method: findEntry(name) */
/**
 * Returns the NameSurferEntry associated with this name, if one
 * exists.  If the name does not appear in the database, this
 * method returns null.
 */
	public NameSurferEntry findEntry(String name) {
		// You need to turn this stub into a real implementation //
		return database.get(name);
	}
	
	HashMap<String,NameSurferEntry> database;
}

NameSurferEntry

/*
 * File: NameSurferEntry.java
 * --------------------------
 * This class represents a single entry in the database.  Each
 * NameSurferEntry contains a name and a list giving the popularity
 * of that name for each decade stretching back to 1900.
 */

import acm.util.*;
import java.util.*;

public class NameSurferEntry implements NameSurferConstants {

/* Constructor: NameSurferEntry(line) */
/**
 * Creates a new NameSurferEntry from a data line as it appears
 * in the data file.  Each line begins with the name, which is
 * followed by integers giving the rank of that name for each
 * decade.
 */
	public NameSurferEntry(String line) {
		// You fill this in //
		this.text=line.split(" ");
	}

/* Method: getName() */
/**
 * Returns the name associated with this entry.
 */
	public String getName() {
		// You need to turn this stub into a real implementation //
		return text[0];
	}

/* Method: getRank(decade) */
/**
 * Returns the rank associated with an entry for a particular
 * decade.  The decade value is an integer indicating how many
 * decades have passed since the first year in the database,
 * which is given by the constant START_DECADE.  If a name does
 * not appear in a decade, the rank value is 0.
 */
	public int getRank(int decade) {
		// You need to turn this stub into a real implementation //
		int rank;
		if (decade==0 || decade==10 || decade==20 ||
			decade==30 || decade==40 || decade==50 ||
			decade==60 || decade==70 || decade==80 ||
			decade==90 || decade==100) {
			int index=(decade)/10+1;
			rank=Integer.parseInt(text[index]);
		}else {
			rank=0;
		}

		return rank;
	}

/* Method: toString() */
/**
 * Returns a string that makes it easy to see the value of a
 * NameSurferEntry.
 */
	public String toString() {
		// You need to turn this stub into a real implementation //
		String result=text[0]+" [";
		for (int i=1;i<text.length-1;i++) {
			result+=text[i]+" ";
		}
		result+=text[text.length-1]+"]";
		return result;
	}
	
	private String[] text;
}

NameSurferGraph

/*
 * File: NameSurferGraph.java
 * ---------------------------
 * This class represents the canvas on which the graph of
 * names is drawn. This class is responsible for updating
 * (redrawing) the graphs whenever the list of entries changes
 * or the window is resized.
 */

import acm.graphics.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;

public class NameSurferGraph extends GCanvas
	implements NameSurferConstants, ComponentListener {

	/**
	* Creates a new NameSurferGraph object that displays the data.
	*/
	public NameSurferGraph() {
		addComponentListener(this);
		// You fill in the rest //
		//init();
	}
	
	
	/**
	* Clears the list of name surfer entries stored inside this class.
	*/
	public void clear() {
		// You fill this in //
		removeAll();
		list.clear();
	}
	
	//删除元素
	public void deletion(NameSurferEntry entry) {
		list.remove(entry);
	}
	
	/* Method: addEntry(entry) */
	/**
	* Adds a new NameSurferEntry to the list of entries on the display.
	* Note that this method does not actually draw the graph, but
	* simply stores the entry; the graph is drawn by calling update.
	*/
	public void addEntry(NameSurferEntry entry) {
		// You fill this in //
		if(list.indexOf(entry)==-1) {
			list.add(entry);
		}
	}
	
	public void show() {
		//记录每个排名的位置
		double d=(getHeight()-2*GRAPH_MARGIN_SIZE)*1.0/MAX_RANK;
		//记录间距
		double distance=getWidth()*1.0/NDECADES;
		//记录上一年的排名
		int last=0;
		//画标签以及直线
		for ( int j=0;j<list.size();j++) {
			NameSurferEntry entry=list.get(j);
			String name=entry.getName();
			//设置颜色
			Color c=color[j%4];
			for(int i=0;i<NDECADES;i++) {
				//获得年份
				int year=10*i;
				//System.out.println(year);
				//获得数量
				int num=entry.getRank(year);
				GLabel text=new GLabel(name+" "+(num));
				if(num==0) {
					text=new GLabel(name+" *");
					num=MAX_RANK;
				}
				
				text.setColor(c);
				//根据增长还是下降调整位置
				add(text,i*distance,GRAPH_MARGIN_SIZE+d*num-text.getHeight());
				
				//扩展功能,增加图形点
				if (j%2==0) {
					GOval object=new GOval(size, size);
					object.setFilled(true);
					object.setColor(c);
					add(object,i*distance-size/2,GRAPH_MARGIN_SIZE+d*num-size/2);
				}else {
					GRect object=new GRect(size, size);
					object.setFilled(true);
					object.setColor(c);
					add(object,i*distance-size/2,GRAPH_MARGIN_SIZE+d*num-size/2);
				}
				//画直线
				if(i>0) {
					GLine line=new GLine((i-1)*distance,GRAPH_MARGIN_SIZE+d*last, 
							i*distance,GRAPH_MARGIN_SIZE+d*num );
					line.setColor(c);
					add(line);
				}
				//更新上一年排名
				last=num;
			}
		}
	}
	
	
	/**
	* Updates the display image by deleting all the graphical objects
	* from the canvas and then reassembling the display according to
	* the list of entries. Your application must call update after
	* calling either clear or addEntry; update is also called whenever
	* the size of the canvas changes.
	*/
	public void update() {
		removeAll();
		init();
		show();
	}
	
	public void init() {
		double distance=getWidth()*1.0/NDECADES;
		for (int i=0;i<NDECADES;i++) {	
			add(new GLine(i*distance,0,i*distance,getWidth()));
			String Year=(1900+10*i)+"";
			GLabel label=new GLabel(Year);
			add(label,i*distance,getHeight()-GRAPH_MARGIN_SIZE+label.getHeight());
		}
		add(new GLine(0,GRAPH_MARGIN_SIZE,getWidth(),GRAPH_MARGIN_SIZE));
		add(new GLine(0,getHeight()-GRAPH_MARGIN_SIZE,getWidth(),getHeight()-GRAPH_MARGIN_SIZE));
	}
	
	
	/* Implementation of the ComponentListener interface */
	public void componentHidden(ComponentEvent e) { }
	public void componentMoved(ComponentEvent e) { }
	public void componentResized(ComponentEvent e) { update(); }
	public void componentShown(ComponentEvent e) { }
	
	private ArrayList<NameSurferEntry> list=new ArrayList<NameSurferEntry>();
	private Color[] color= {Color.BLACK,Color.RED,Color.BLUE,Color.magenta};
	//private GObject object;
	private int size=5;
}