装订线
北京师范大学2015~2016学年春季学期期末Java程序设计作业试卷课程名称: Java程序设计任课教师姓名:孙一林
卷面总分: 100 分考试时长:分钟考试类别:闭卷□开卷
其他□院(系):信息科学与技术学院专业:计算机科学与技术年级: 2014 姓名:刁诗哲学号:
阅卷教师(签字):
评价准则:
(1)应用程序设计思想………………………………………………… ≤ 20% (2)程序结构表述……………………………………………………… ≤ 20% (3)调试、运行、结果………………………………………………… ≤ 20% (4)报告+程序文档………………………………………………………≤ 20% (5)应用程序展示(5分钟讲解与演示)……………………………≤ 10% (6)应用程序难易度……………………………………………………≤ 10%
设计要求:
选择一题,按自己理解设计程序,在报告(该试卷首页为报告第1页,文件名及格式为:*.doc或*.docx,* = 学号 + 姓名,报告为必要项)中给出设计思路、程序结构、调试、模拟运行、结果等说明内容,提交作业(设计、调试、运行、结果):报告+程序所有(源程序、类、打包等)文件的压缩文档(学号 + 姓名)。设计题目难易度依照题号顺序由小到大。
多功能日历记事本
一、整体介绍
1.外观显示
日历外观如下图所示,全局大体分为四个部分:左上,左下,右上,右下。
最上面是标题栏,显示该程序的名称,如我的程序显示的为“刁诗哲的日历”。标题栏下方为菜单栏,菜单栏目前有两个菜单,分别是“功能设置”和“关于”。
左上部分为日历界面,显示一个万年历,用户可以在输入框中输入所查年份和月份,按下回车后自动跳转到该月。左下部分是显示图片部分,用户可以自主设置自己喜欢的图片,设置这一功能主要是给用户提供个性化的用户体验,可以根据自己的喜
好设置喜爱的图片,比如放置一个名人座右铭可以勉励自己在学业上不断进步。右上为记事本区域,用户可以选中日期后输入自己想要保存的记事,同时,用户可以设置提醒时间(闹钟)。在右下方是一个钟表,不仅可以为用户提供实时查看时间的服务,同时也可以作为闹钟使用。
2.基本功能
1)万年历功能
左上方的日历相当于一个万年历,可以为用户提供一个日期的查看功能,可以显示日历的年月日,并且对今天的日历给出了特殊的显示(大字体和蓝色显示)。还能查看当前时间之前和之后的日历,可以通过按钮操作,也支持在输入框里面输入年和月。如上图
2)记事本的编辑、查看和删除功能
右上方提供备忘录(记事本)功能,用户可以记录下来之前发生的事情以作纪念,也可以记录下来未来想要做的事情以防遗忘
3)闹钟功能
用户点击设置闹钟时间后,便可以设置闹钟时间,到达预定时间后闹钟会播放音乐,当然,闹钟提醒音乐也可以自己设置。
4)使用帮助
3.高级功能
1)时区设置
我们为用户提供了多达75个时区的选择,点击更改时区即可将时间切换到当前用户所在的时区,可以满足用户去往不同国家的需求。是一款“国际化”日历。
2)自定义图片
用户点击更改图片背景,可以选择自己喜欢的图片,为用户提供了多样化选择。可以根据自己的喜好设置喜爱的图片,比如放置一个名人座右铭可以勉励自己在学业上不断进步。
3)自定义音乐
考虑到普通闹钟刺耳的缺点,我们给用户提供定制化铃声的功能,让用户可以自己设置闹钟铃声,提供了个性化的用户体验。
4)保留自定义设置
用户的自定义设置功能都会被记录,下次打开软件时还能保留先前的设置。是一款真正的人性化、个性化日历
二、设计思路
首先,按照功能将日历分成不同模块,分别是CalendarImage(显示图片),CalendarPad(实现主要功能,主要框架),mainclass(main方法),NotePad(显示
记事本),myClock(钟表的显示),Month(月份的设置和显示),Year(年份的设置和显示)。
图 1 根据功能设计日历模块
首先按照日历所要实现的功能,从外观显示和内部功能设计日历。
日历的外观共分为四个部分,分别是顶部的菜单栏,左上部分显示日历面板,右上部分显示记事本面板,左下部分显示图片,右下部分显示表盘,包括电子表显示和钟表表盘显示。
日历的内部功能:
实现记事本功能:包括获取日志,显示日志,删除日志
实现闹钟功能:包括钟表的显示,不同时区的设置,和到时提醒功能
日历日期的显示:包括月份的设置,年份的设置
根据以上功能的划分,按照面向对象编程的设计思想,将同一对象所应用的功能合并到一个对象上,可以将日历的实现划分为以下几个模块。
图 2 面向对象的日历设计
三、程序结构
1.总体结构
在设计多功能日历时,需要编写7个java源文件:mainclass.java, mainclass.java, NotePad.java , Year.java, Month.java,CalendarImage.java ,myClock.java。这些类的主要功能如下:
主类 mainclass(用于启动程序)
主要框架mainclass(是程序的核心)
记事本NotePad(记事本功能)
年Year(显示年)
月Month(显示月份)
日历图像CalendarImage(显示日历图像)
数字时钟myClock(用于显示数字时钟)
类之间的关系如下图所示
2.详细设计
mainclass.java
package diaoshizhe;
import java.util.Calendar;
//这是程序的主类;程序从这个类开始;
public class mainclass {
public mainclass() {
}
//main方法;
public static void main(String args[])
{
//创建一个日历的实例对象,返回当前时间;
Calendar calendar=Calendar.getInstance();
int y=calendar.get(Calendar.YEAR);
int m=calendar.get(Calendar.MONTH)+1;
int d=calendar.get(Calendar.DAY_OF_MONTH);
//新建一个CalendarPad类的对象,以参数形式传递获取的当前时间
new CalendarPad(y,m,d);
}
}
CalendarPad.java
成员变量:
int year,month,day; //存储当前的时间;
Calendar calendar; //日历对象;
int day_of_the_week; // 表示具体的星期几;
NotePad notepad=null; //记事本对象变量;
Month showMonth; //显示月份的区域的组件对象
Year showYear; //显示年份的区域的组件对象
Hashtable hashtable; //哈希表对象,用于写日志时文件的IO流;
File file; // file表示文件对象,用于写日志时文件的IO流;
JTextField showDay[]; // 单行文本编辑区域数组,用于显示日期;也是日历中每天的显示区域;
JLabel title[]; //标题栏,主要用于日历中星期几的标题栏;
CalendarImage calendarImage;//日历图像;
String picturename;//图像名称;用于更换图像时记录文件名
static String musicname;//音乐名称;用于用户更换闹钟铃声时记录文件名
String weekDay[]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
JPanel leftUp,rightUp,leftWhole,rightWhole;//创建;
int ringhour,ringmin;
myClock clock;//时钟对象;
static String timeArea="Asia/Shanghai";
方法:
//构造方法
public CalendarPad(int year,int month,int day)
//增加鼠标监听器,按住鼠标的响应,为读取日志、写日志功能服务;
public void mousePressed(MouseEvent e) // 增加鼠标按钮的触发;
public void mouseClicked(MouseEvent e)
public void mouseReleased(MouseEvent e)
public void mouseEntered(MouseEvent e)
public void mouseExited(MouseEvent e)
//getPicture_address()方法,从文件中读到用户选择的图片文件的地址;
public String getPicture_address()
//getMusic_address()方法,从文件中读到用户选择的闹钟铃声文件的地址;
public String getMusic_address()
//getsettingtime()得到闹钟时间,从文件中读到先前设置的闹钟时间;
public void getsettingtime()
// 设置日历牌,但只是起到对不同月份的分类而已,通过调用sortDay()方法,把每个格要显示几号的任务交给调用方法;
public void setCalendar(int year,int month)
// 此方法供setCalendar()调用,用来设置每个格要显示几号;
public void sortDay(int day_of_the_week,int月天数)
//得到年;
public int getYear()
//设置年;
public void setYear(int y)
//得到月份;
public int getMonth()
//设置月份;
public void setMonth(int m)
//得到号数;
public int getDay()
//设置号数;
public void setDay(int d)
//获得hashtable;
public Hashtable, ?> getHashtable()
//获得文件;
public File getFile()
//事件监听器;
public void actionPerformed(ActionEvent e)
NotePad.java
成员变量:
JTextArea text;//定义一个编辑区域;
JButton save,delete;//定义两个按钮,保存,删除;
Hashtable
JLabel labelBar; //用于显示日期的标题;
int year,month,day;
File file;
CalendarPad calendar;
方法:
//构造函数,实现记事本显示、增删的主要功能;
public NotePad(CalendarPad calendar)
//监听按钮事件;
public void actionPerformed(ActionEvent e)
//设置年
public void setYear(int year)
//获取年;
public int getYear()
//设置月份;
public void setMonth(int month)
//获取月份;
public int getMonth()
//设置日;
public void setDay(int day)
//获取日;
public int getDay()
//设置标题栏的内容(日期);
public void setlabelBar(int year,int month,int day) //设置编辑区域显示的内容;
public void setTextArea(String s)
得到某个日期的日志内容;
public void getLogContent(int year,int month,int day) //保存日志的方法;
public void saveLog(int year,int month,int day)
//删除日志
public void deleteLog(int year,int month,int day)
myClock.java
package diaoshizhe;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.io.File;
import https://www.wendangku.net/doc/5d17722904.html,.MalformedURLException;
import https://www.wendangku.net/doc/5d17722904.html,.URL;
import javax.swing.*;
import java.util.*;
import java.text.*;
public class myClock extends JApplet implements Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
Thread clock;
int ringhour;
int ringmin;
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone(CalendarPad.timeArea));
Date timenow;
Clock nowClock;
public myClock(){
start(); //开始进程
int w=getBounds().width;
int h=getBounds().height;
setBounds(0,0,w,h); //设置窗口尺寸
}
public void start(){
if (clock == null) {
clock = new Thread(this);
clock.start();
}
}
public void stop() {
clock = null;
}
public void run(){
while(true) {
repaint();
try{
Thread.sleep(1000);
}
catch(InterruptedException e){
}
}
}
@SuppressWarnings("deprecation")
public void paint(Graphics g) {
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone(CalendarPad.timeArea));
timenow = new Date();
calendar.setTime(timenow);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss a");
sdf.setTimeZone(TimeZone.getTimeZone(CalendarPad.timeArea));
String s_time_msg = sdf.format(timenow);
nowClock = new Clock(
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
calendar.get(Calendar.SECOND) );
g.clearRect(0,0,this.getWidth(),this.getHeight());
g.setFont(new Font("宋体", Font.BOLD, 22));
g.drawString(s_time_msg,70,400);
nowClock.show(g,230,210,150);
//闹钟功能:如果当前时间与设置的闹钟时间相同,则响铃;
if((ringhour==calendar.get(Calendar.HOUR_OF_DAY))&&(ringmin==calendar.ge
t(Calendar.MINUTE))&&(calendar.get(Calendar.SECOND)==0))
{
//播放指定音频;
try {
URL cb;
File f = new File(CalendarPad.musicname);//音频文件;
cb = f.toURL();
AudioClip aau;
aau = Applet.newAudioClip(cb); //创建AudioClip对象;
aau.play();//播放音频;
} catch (MalformedURLException e)
{
e.printStackTrace();
}
}
}
}
class Clock {
int hour,minute,second;
Clock(int hrs,int min,int sec) {
hour = hrs%12;
minute = min;
second = sec;
}
void show(Graphics g,int cx,int cy,int rad) {
int hrs_len = (int)(rad*0.5);
int sec_len = (int)(rad*0.9);
double theta;
g.drawOval(cx-rad,cy-rad,rad*2,rad*2);
theta=(double)(hour*60*60+minute*60+second)/43200.0*2.0*Math.PI ;
drawNiddle(g,Color.blue,cx,cy,hrs_len,theta);
theta=(double)(minute*60+second)/3600.0*2.0*Math.PI ;
drawNiddle(g,Color.red,cx,cy,sec_len,theta);
theta=(double)(second)/60.0*2.0*Math.PI ;
drawNiddle(g,Color.green ,cx,cy,sec_len,theta);
}
private void drawNiddle(
Graphics g,Color c,int x,int y,int len,double theta){
int ex = (int)(x+len*Math.sin(theta));
int ey = (int)(y-len*Math.cos(theta));
g.setColor (c);
g.drawLine(x,y,ex,ey);
}
}
Year.java
package diaoshizhe;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//继承Box,显示日历上的年份
public class Year extends Box implements ActionListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
int year; //定义年;
JTextField showYear=null;//显示年的区域;
JButton nextYear,lastYear;//定义按钮;
CalendarPad calendar;//日历;
//构造方法;
public Year(CalendarPad calendar)
{
super(BoxLayout.X_AXIS);//用super继承父类的构造方法,box中的组件从左到右布置器件;
showYear=new JTextField(4); //区域大小设置;
showYear.setForeground(Color.blue); //显示字体颜色;
showYear.setFont(new Font("TimesRomn",Font.BOLD,14)); //设置字体,大小;
//把calendar的时间传进来;
this.calendar=calendar;
year=calendar.getYear();
//新建按钮;
nextYear=new JButton("下年");
lastYear=new JButton("上年");
//添加按钮;
add(lastYear);
add(showYear);
add(nextYear);
//添加事件监听器;
showYear.addActionListener(this);
lastYear.addActionListener(this);
nextYear.addActionListener(this);
}
//设置年;
public void setYear(int year)
{
this.year=year;
showYear.setText(""+year);
}
//获取年;
public int getYear()
{
return year;
}
//事件监听方法;
public void actionPerformed(ActionEvent e)
{
//如果点击的是lastyear按钮;
if(e.getSource()==lastYear)
{
//年减去一年,重新设置日历;
year=year-1;
showYear.setText(""+year);
calendar.setYear(year);
calendar.setCalendar(year,calendar.getMonth()); }
//如果点击的是nextyear按钮;
else if(e.getSource()==nextYear)
{
//年增加一年,重新设置日历;
year=year+1;
showYear.setText(""+year);
calendar.setYear(year);
calendar.setCalendar(year,calendar.getMonth());
}
//如果是在显示年的区域内写入东西;
else if(e.getSource()==showYear)
{
try
{
//获取写在该区域的内容,转化为整型,赋给year,重新设置日历;
year=Integer.parseInt(showYear.getText());
showYear.setText(""+year);
calendar.setYear(year);
calendar.setCalendar(year,calendar.getMonth()); }
catch(NumberFormatException ee)
{
showYear.setText(""+year);
calendar.setYear(year);
calendar.setCalendar(year,calendar.getMonth()); }
}
}
}
Month.java
package diaoshizhe;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//继承Box,用于显示日历上的月份,并可选择上月,下月;
public class Month extends Box implements ActionListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
int month;
JTextField showMonth=null;
JButton nextMonth,lastMonth;
CalendarPad calendar;
public Month(CalendarPad calendar)
{
super(BoxLayout.X_AXIS);//用super继承父类的构造方法,box中的组件从左到右布置器件;
//把calendar的时间传进来;
this.calendar=calendar;
showMonth=new JTextField(2);//区域大小设置
month=calendar.getMonth();
showMonth.setForeground(Color.blue); //显示字体颜色
showMonth.setFont(new Font("TimesRomn",Font.BOLD,16)); //设置字体,大小;
//新建按钮;
nextMonth=new JButton("下月");
lastMonth=new JButton("上月");
//添加按钮;
add(lastMonth);
add(showMonth);
add(nextMonth);
//添加事件监听器;
showMonth.addActionListener(this);
lastMonth.addActionListener(this);
nextMonth.addActionListener(this);
showMonth.setText(""+month);
}
//设置月份;
public void setMonth(int month)
{
if(month<=12&&month>=1)
{
this.month=month;
}
else
{
this.month=1;
}
showMonth.setText(""+month);
}
//获取月份;
public int getMonth()
{
return month;
}
//事件监听方法;
public void actionPerformed(ActionEvent e)
{
//按下lastMonth按钮
if(e.getSource()==lastMonth)
{
//如果month>2,则month直接减1,重设置日历;
if(month>=2)
{
month=month-1;
calendar.setMonth(month);
calendar.setCalendar(calendar.getYear(),month);
}
//如果month==1,则year-1,而month为12,重设日历;
else if(month==1)
{
month=12;
int year=calendar.getYear()-1;
calendar.setMonth(month);
calendar.setYear(year);
calendar.setCalendar(year,month);
}
showMonth.setText(""+month); //显示内容的设置;
}
// 如果nextMonth按钮被按下;
else if(e.getSource()==nextMonth)
{
//如果month小于12,则month直接加1,再重设日历;
if(month<12)
{
month=month+1;
calendar.setMonth(month);
calendar.setCalendar(calendar.getYear(),month);
}
//如果month=12,那么year+1,并且month变为1,再重设日历;
else if(month==12)
{
month=1;
calendar.setYear(calendar.getYear()+1);
calendar.setMonth(month);
calendar.setCalendar(calendar.getYear(),month);
}
showMonth.setText(""+month);//设置显示内容;
}
else if(e.getSource()==showMonth)
{
month=Integer.parseInt(showMonth.getText());
if((month>=1)&&(month<=12)){
try
{
calendar.setMonth(month);
calendar.setCalendar(calendar.getYear(),month);
}
catch(NumberFormatException ee)
{
//showMonth.setText(""+month);
calendar.setMonth(month);
calendar.setCalendar(calendar.getYear(),month);
}
}
showMonth.setText(""+month);
}
}
}
CalendarImage.java package diaoshizhe;
import javax.swing.*;
import java.io.*;
import java.awt.*;
//继承了JPanel类,用于显示图片;
public class CalendarImage extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
File imageFile;//定义文件;
Image image;//定义图片;
Toolkit tool;//定义工具;
//构造方法
public CalendarImage() {
tool=getToolkit();//获取工具;
}
//设置图像文件;
public void setImageFile(File f)
{
imageFile =f;
try{
image=tool.getImage(imageFile.toURI().toURL());//得到图像文件;
}
catch (Exception eeee)
{
}
repaint();//重绘;
}
//重载paintComponent方法
public void paintComponent(Graphics g)
{
super.paintComponent(g);
int w=getBounds().width;
int h=getBounds().height;
g.drawImage(image,0,0,w,h,this);
}
}
四、调试
在调试过程中遇到了很多问题,可以说是一边写代码一遍调试的(个人认为这也是正确方法,如果写完所有代码再调试就太晚了),在调试的过程中遇到了很多问题,在这里举最关键的,印象最深的问题列举。
遇到的问题1:
日历面板如何设计,怎样才能较完整的实现日历的功能,在这个方面的设计我头脑有点晕,分不清几个模块如何拼接在一起。如何显示日历面板,通过百度我搜索了一下前人的经验,又看了一些优秀案例,同时参照自己电脑上的日历,有了解决方法。
解决:
设置一个大的JPanel叫做leftUp(因为左上角是日历,所以名字叫leftUp),然后设置几个小的组建,分别是
JPanel leftUp_center=new JPanel();// leftUp_center为窗口的leftUp的中间部分,用于显示日历;
JPanel leftUp_north=new JPanel();//leftUp_north为窗口的leftUp的上部分,用于显示年月及相关按钮;
JPanel leftUp_center_east=new JPanel();//leftUp_center_east是窗口的leftUp_center的东边部分,用来显示日历每天的星期和号数;
使用以上方法就将一个大的日历划分成几个小的模块,然后一一实现就简单了