万年历查询系统课程设计报告.docx
领南甯老就面向对上程方世计课程设计报告题目万年历查询系统姓名:学号:专业:一计算机科学与技术一班级:计科指导教师:职称:讲师计算机与电子工程学院2009年6月课程设计评审表姓名学院计算机与电子工程学院学号专业班级计科题目万年历查询系统评审意见评审成绩指导教师签名职称评审时间年月日课程设计作品验收表题目万年历查询系统参与人员姓名班级计科学号设计任务与要求:作品完成情况:验收情况:验收教师签名:注:1.除“脸收情况”栏外,其余各栏均由学生在作品脸收前填写。2.“验收情况”栏由脸收小组按实际验收的情况如实填写。1课程设计过程概述12课程设计题目描述和基本设计要求13系统需求分析13.1 功能需求分析13.2 其他需求分析24系统设计24.1 总体设计24.2 数据存储设计34.2.1 静态数据34.2.2 计算数据44.3 万年历查询系统界面设计44.4 各功能模块设计64.4.1 阳历日期显示设计64.4.2 农历日期显示设计74.4.3 节气节日显示设计84.4.4 下拉表与今天的查询功能设计94.4.5 系统时钟时间显示设计104.5 异常处理情况说明105系统实现与调试116课程设计总结126.1 遇到的问题及解决办法126.2 心得体会13参考文献13附录14万年历查询系统1课程设计过程概述在2009年6月,学院对我们进行了为期两周的JaVa课程培训,我们按要求在实验楼二楼网络机房进行了学年度课程设计。这次课程设计的主要目的是结合面向对象程序设计课程,培养我们面向对象软件开发的思维,提高用JaVa编程的实际动手能力并增强大家对面向对象的了解。这次课程设计的主要内容是独立用Java语言开发一个小的应用程序、网络应用程序或者是管理系统,从而深刻体会面向对象软件开发的方法。2课程设计题目描述和基本设计要求我设计的是一个万年历。万年历,实际上就是记录一定时间范围内(比如100年或更多)的具体阳历或阴历的日期的年历,方便有需要的人查询使用。在我设计的万年历中,按月份查询,实现了显示查询19012100年某月所有日期的阴阳历对照,并且添加了二十四节气与重大节日等信息,界面采用日常的星期与月份结合的格式,方便查看与使用。基本设计要求如下:(1)能够实现显示19012100年的日期,包括公历、农历、星期、二十四节气;(2)能够按照月份格式显示,或按照星期格式显示;(3)能够显示系统日期;(4)尽量使用图形界面实现,要符合日常软件使用规范。3系统需求分析3.1功能需求分析为了实现一个万年历的功能,首先需要了解阳历日期是怎样分布的;其次,要实现星期与月份格式的显示,则需了解每个月有多少天,这个月的第一天是星期几一一称为初始星期;要实现阳历与农历信息的同步查询,则必需了解农历日期的分布规律;最后,节气与节日的显示则要找到万年历涉及的年份的节气表,重大节日的规律还是很简单的,反正每年的节日都是固定的,只用一个表就可以查询了。3.2其他需求分析(1)性能描述界面友好、简洁,查询操作简单,查询完后应该随时都能回到今天的信息当中。(2)设计平台开发工具:jdkl.6和eclipse3.2;运行环境:WindoWS2000以上;(3)界面要求以WindoWS窗口形式显示,右上角有最小化按钮、关闭按钮;设置两个下拉表用于查询年月,一个今天按钮用于返回当日信息。4系统设计4.1 总体设计我设计的万年历查询系统主要功能就是查询与显示。交互界面只有查询与显示当日信息两项,所有信息都已经由数据表与算法结合的方式实现,显示信息由事件调用算法自动刷新。其处理过程图如下:I-开始|一当日信息查询|一|查询信息今日关闭图1信息处理图4.2 数据存储设计4.2.1 静态数据(1)星期在java.util.Calendar.getTime()中返回的是英文信息如“sun”,为了便于识别,将其转换成相应的中文“星期日",以字符串数组的形式存储,两个数组一一对应,便于实现转换,源代码如下:privateStringStringWeekEn=newStringSUN,“MON",叮UE“,“WED",“THU”,FR,“SAT”;privateStringStringWeekCn=newString“星期日”,“星期一”,“星期二”,“星期三星期四","星期五”,“星期六”;(2)月份月份的存储同星期,以英汉对照式的数组存储,同样便于存取转换。(3)农历农历的算法实现异常困难,这里采用数据表的形式将农历信息保存,使农历与阳历的转换变得易于实现,但这也限制了农历表的实现只能查询到表中的有限个。表中每个十六进制数存有一年的信息,第一位保存闰月信息,中间三位保存12个月的信息,最后一位说明今年闰月是几月。以0x04bd8为例,是保存了1900年的农历信息,最后一位说明今年八月是闰月;第一位要么为0,要么为1,为0说明闰月只有29,为1则闰月为30天;中间三位展开来看有多少位为1,为零的这个月有29天,为1的这个月有30天。finalprivatestaticlongIunarInfo=newlong0x04bd8,0x04ae0,0x0a570,OxO54d5,0x0d260,0x0d950,0x16554,OxO56aO,0x09ad0,0x055d2,);(4)节气节气同农历的存储一样没有任何规律可言,只能利用数据表的方式将各年的节气信息保存。上面列出的数据是1900年的节气表,一年24个节气,每个月两个,利用多维数组对应存储,方便取出信息。表1节气表数据类型数据大小Tnt7*12*2String12*2privatefinalstaticintSolarTermDate=newint6,20,4,18,6,2i,5,20,6,21,6,22,7,23,8,23,8,23,9,24,8,23,7,22privatefinalstaticStringSolarTerm=newString"小寒'',"大寒'',“立春",”雨水”,("惊蛰”,"春分”,“清明”,"谷雨叽“立夏”,“小满”,“芒种”,“夏至”,“小暑”,“大暑”,“立秋”,"处暑叽“白露”,“秋分叽“寒露”,“霜降叽“立冬”,“小雪”,“大雪”,“冬至”;(5)节日表同节气表,不再赘述。4.2.2 计算数据(1)阳历月份天数计算46911几个小月返回29天,2月经过判断是否为闰年,选择返回28或29天,其余月份为大月,返回31天。(2)查询月份的初始星期java.util.Calendar.set(intyear,intmonth,intdate)设置日历类的信息,把date设置为1即为这个月第一天,再由java.util.Calendar.getTime()返回英文表示的星期信息,即这个月的初始星期。4.3 万年历查询系统界面设计(1)窗体的设计窗体整个框架使用javax.swing.JFrame类构造,JFrame使用add()添加组件,我在万年历中添加了了三个javax.swing.JPanel类来对JFrame格式化,实际上也就是将窗体分成了上中下三部分。JPanel中的SetGridLayoUt(introws,intcols,inthgap,intvgap)方法可以将JPanel按指定的行、歹(I、水平间距、垂直间距进行分区,类似于表格形式,比如setGridLayout(1,3»10,0)表示将JPanel分成1行3列,水平间距为10,垂直间距则可以是任意值,由系统自动调节。并且通过将javax.swing.JComboBox,javax.swing.JButoon,javax.swing.JLabel添加到相应JPanel上实现整个窗体的融合。我在万年历中用JPanel进行了以下分区:下拉表1下拉表2I今天按钮系统时间星期日星期一星期二星期三星期四星期五星期六图2窗体设计图JFrame在其右上角都有三个控制图标,分别代表将窗口最小化、窗口最大化和关闭的操作,其中最小化和最大化操作JFrame可自动完成,而关闭窗口操作实现需要书写有关的代码,在我的程序中我采用的是引发WindOWSEVent类代表的窗口事件。相应源代码为:addWindowListener(newWindOWAdaPter()窗口侦听器,以从此窗口接收窗口事件publicvoidwindowClosing(WindowEvente)处理窗口关闭事件System.exit(O););)(2)下拉表的设计javax.swing.JcomboBox是实现下拉表的一个类,在我的万年历中使用了两个下拉表,一个用于查询年份,一个用于查询月份。它们的位置如图2所示。(3)按钮的设计在我的万年历中只有一个按钮,其目的是为了随时都能当日信息的显示中,位置如图2所示。(4)星期与日期的显示设计如图2所示,按星期与月份的格式排列,一个月至少要有12行才能保证信息显示完全,其中阳历日期与农历日期隔行显示,使用了12*7=84个标签。4.4 各功能模块设计4.4.1 阳历日期显示设计在java中实现阳历的查询异常方便,因为java.util.GregorianCalendar这个类就是处理日历信息的,它几乎集成了所有日历属性,我们只要调用其中的某个方法就能很方便地得到我们想要的信息了。在我的万年历中需要查询某月或返回今日信息时,都是调用GregorianCalendar中的方法来实现的。GregorianCaIendar.getTime()返回一个date类,将date通过date.toString().split(ii)方法返回一个字符串数组存于SySNoWTime中,调用SySNoWTime即能得到当日的年月日初始星期等信息,这样就能将当前信息贴上标签显示出来了,添加阳历信息后的万年历效果如(图3)o初始星期对应标签labelOi,i取06,将Iabel0i的内容设为1,代表这个月的1号,设这个月有month天,循环month次,依次将对应标签内容设为日期。因为日历不仅要显示阳历信息,还要显示农历信息,所以阳历日期的排列是隔行排列的,即由IabeI跳至Iabel,再由Iabel跳至Iabel,以此类推。为了实现这个功能,我用了一个SWitCh语句,源代码如下:al=i7;i即为当前表示的日期,al表示数组的第一维下标switch(al)case0:al=0;break;case1:al=2;break;case2:al=4;break;case3:al=6;break;case4:al=8;break;case5:al=10;break;星蝴日星期一1星期二2星期三3星期四4星期五5星蝴六6789101112131415161718192021222324252627282930图3添加阳历信息后的万年历效果图4.4.2 农历日期显示设计阴阳历法换算,尽管有不少专家学者一直苦苦寻找一个固定的程式,但至今仍没有结果。目前我们日常使用的万年历均是参照1993年出版的中美天文万年历一书制定,但书中精确的天文日月时间只从1900到2010年,所以我的万年历中也只用查表的方式实现了这些年份的显示。农历算法已经实现,再在阳历已经实现的基础上添上农历信息就不难了,所以这里简述一下农历是怎么算出来的。要算出某年某月某日的农历日期,只能采用逐日递推的方式,这里以1900年1月31的日期为依据,它的农历日期为一九零零年大年初一,调用日历类GregOrianCaIendar可以算出所求日期与1900年1月31日相差多少天,设这个差值为OffSe3则用OffSet与19002100的农历年天数逐个相减,当OffSet<=0时,可以确定当前农历年份。再用相减后得到的OffSet与得到的年份的农历月天数逐个相减,同理,当OffSet<=0时可以确定农历月份。最后,OffSet加上当前月份的天数就可以得到农历日期了,至此,阳历与农历的转换算法得以实现。在排列阳历日期时,调用阳历与农历的转换算法得到相应农历日期,将对应阳历日期标签下的内容设为农历日期,核心源代码如下:for(inti=initWeek;i<initWeek+monthDays;i+)IabelDaya1a2.setText(String.valuef(i-initWeek+1);labelDayal+la2.setText(getChinaDate(int)(12);)最后效果图如图4o国万年历程序一Star1Q.旦!一组J2009年六月今天13:51:19星蟠日7星期一1初九8星期二2初十9星期三3十一10星期四4十二11星期五5十三12星蝴六6十四13十五十六十七十八十九二十廿一14151617181920廿二廿三廿四廿五廿六廿七廿八一21222324252627廿九三十初一初二初三初四初五282930初六初七初八图4添加阳历与农历信息后效果图4.4.3 节气节日显示设计二十四节气的分布没有单一的规律可言,但是就一定时期来看,它的分布还是有据可循的,在我的万年历中用查表的方式实现了近200年的节气查询。每个月两个节气,只要确定了年份与月份,就可以到节气数表SOlafrermDate川取出是哪两天,将对应标签的内容用节气覆盖农历日期,所以节气信息比农历节日信息优先显示。节日的分布是固定的,较之节气来说,更容易操作和实现,我假设每个月份三个节日,在排列中,只需取出每个月的三个节日的日期比较一下,相等就把日历信息修改一下,所以节日有较节气信息优先显示。部分源代码如下:显示二十四节气if(i-initWeek+1)=SolarDay)IabelDayal+1a2.setText(solarTermmonth-1U+);if(j<=1)solarDay=solarTermDatearrmonth-1j;1显示每个月的节日if(i-initWeek+l)=sFtvDay)if(sFtvmonth-lk!=null)IabelDaya1+1a2.setText(sFtvmonth-1k+);IabelDaya1+1a2.setFont(newFom(“黑体“,Font.BOLD,8);)if(k<=2)sFtvDay=sFtvDatemonth-1k;1最后,添加上节气与节日的万年历显示完成其效果如(图5):LiJ万年历程序一StWI。回I次!2009年六月今天13:59:20星期日星期一星期二星期三星期四星期五星豳六123456初十H-一十二芒种十四78910111213十五十六十七十八十九二十廿一14151617181920廿二廿三廿四廿五廿六廿七廿八21222324252627夏至三十初一初二初三初四初五282930初六初七初八图5添加节气节日信息后的万年历效果图4.4.4 下拉表与今天的查询功能设计在我的万年历中定义了一个响应选择下拉表事件的方法SetChangeDateO,这个方法需要做以下两件事:算出所选择的年月信息;用得到的信息调用显示方法刷新显示内容。在一个下拉表中javax.swing.JComboBox.getSelectedIndex()可以返回当前选中的下拉表内容的序号,这个序号加上1900即为所查找年份。同理可得到查找的月份。得到的年月作为java.util.Calendar.set(intyear,intmonth,inidate)的参数,date设为1即这个月的第一天,得到这个月的初始信息,这样完全可以将这个月的信息显示出来了。查询功能实现。今天这个按钮的功能实现与下拉表大同小异,只是定义的响应方法不同,将上面Calendar.set(intyear,intmonth,intdate)的参数修改为当日信息即可。4.4.5 系统时钟时间显示设计javax.swing.Timer这个类可以方便地实现对时钟时间的操作,Timer类大多用于计划功能,这里用于刷新系统时间的显示,javax.swing.Timer.Timer(intdelay,ActionListenerlistener)delay可以设置隔多长时间执行任务,IiStener即用于监听的事件,每隔一定时间执行一次,这里delay以毫秒为单位,设为I(M)0,实际上就是一秒,这样闹钟就能每秒钟刷新一次,保证时间显示正确。它的部分源代码如下:classTimerListenerimplementsActionListenerpublicvoidactionPerformed(ActionEvente)GregorianCalendarg=newGregorianCalendarO;Stringclock=newString(g.getTime().toString().split(u',)3);labelTime.setText(clock);)添加时钟后效果图可以在图5中看到。4.5 异常处理情况说明在我编写万年历的过程中主要遇到了以下几种异常情况,最后都得以成功处理。(1) NUlPointerEXCPtion(空指针异常)引起空指针异常的原因主要有两个:引用了没有初始化的变量或类;逻辑错误。最后我发现是自己的IabelDay口口数组后面有一部分没有初始化,初始化得以解决。(2) ArraylndeXe)Ute)fBoundsException(数组越界异常)要解决这个问题当然得保证使引用的数组不会越界,引起的原因也有两个:自己定义的数组够用,但是引用过程中计算出错,导致异常,这样检查起来也较困难;另一种情况是定义的数组长度小了,一般来说很容易发现。我遇到的异常是由于计算错误导致,阳历日期的排列是隔行的,label。的第一维跳跃前进,即按0-2-4-6-8-10这种规律前进,我算成了1-3-5-7-9-11,导致数组越界。(3)逻辑异常我说的逻辑异常是指没有报错、没有异常警告的情况下,程序总是不能得到期望的结果。我在万年历的设计中遇到了这种异常,是由于自己对数组的使用不够熟练所致。调用GregOrianCalendar类返回的月份信息是按日常生活得习惯从1-12排列的,而数组的下标是从。开始的,我在处理而者时没有进行转换,结果总是不能得到正常结果。5系统实现与调试(1)系统实现在安装jdkl.5以上版本的计算机上可以用Dos运行,也可以借助Eclipse等编译工具实现。万年历的显示如(图6),它的操作很简单,选中年份下拉表选择年份,选中月份下拉表选择月份,就可以查询到某年某月的每天的信息了。查询完毕后,点击”今天”将回到当前月的显示,其中篮框突出显示的为今天的日期,(图6)显示的是2009年6月27,农历日期六月初五。图6万年历显示界面(2)调试随意选择一个年份和月份,用查询结果与我下载的一个万年历软件进行比较,重复多次,测试结果没有一丝差错。在每次查询完后点击今天按钮,每次都能回到今天的界面O6课程设计总结6.1 遇到的问题及解决办法在此次课程设计中,我遇到了一些问题,如:对于面向对象的方法了解不够透彻,运用到实际的软件开发中存在着困难;对于JaVa语言,只学习到了一些最基本的知识,这导致编写程序时经常出现一些语法错误,而且要在短时间内用JaVa语言来设计一个具体的系统是一个较大的挑战;还有对于正规开发一个系统的流程不熟悉,适应起来比较慢,编写各个模块相对应的操作时,自己感觉难以动手,这表明所学的知识不能灵活运用到实际中。对于以上的问题,自己有清楚的认识,解决办法是需要大量阅读相关的书籍,对于书上以及网站上下载的资料中的JaVa实例必须有清楚的理解,还有就是多跟精通此方面的老师和同学交流,取其精华。对于实际动手能力与系统开发的流程的适应,必须多进行实际的练习与操作,才能有大的进步。6.2 心得体会在这次的学年度课程设计中,我主要运用了JaVa语言的界面设计、异常处理、Awt控件、SWing控件、输入输出流等,综合运用了JaVa语言。我深刻感受到了面向对象语言中类库的强大功能,掌握了运用JaVa中的类实现某些基本功能,并学会了自己查询使用类的方法,为以后的面向对象语言的自学奠定了基础。通过这次为时十天的课程设计,我学到了很多的东西,下面就这在这次课程设计中的心得体会总结如下:在这次课程设计中,主要是运用JaVa语言来编写,并可运用其他的技术。在我的系统中,还采用了SWing控件、输入输出流等技术,而这些知识都是我们没有学过的,这就要求我们去查阅相关书籍。正因为这样,才锻炼了我的自学能力,为以后的学习打下了基础。此外,我还深刻感受到了面向对象语言中类库的强大功能,掌握了运用Java中的类实现某些基本功能,并学会了自己查询使用类的方法,为以后的面向对象语言的自学奠定了基础通过十天的努力,这次课程设计圆满的结束了,在这个过程中,我学到了很多的知识,同时也非常感谢刘耀老师的帮助与指导。在以后的学习中,我会更加努力的学好专业知识,并将所学知识用于实践当中去,以便牢固掌握知识。参考文献1朱福喜,傅建明.JAVA项目设计与开发范例M.北京:电子工业出版社,2005.2王强,贾素玲.JAVA程序设计M.北京:清华大学出版社,2007.3王文涛,袁海燕.JAVA实用程序设计100例M.北京:人民邮电出版社,2005.4雍俊海JAVA程序设计M.北京:清华大学出版社,2006.5刘宝林.JAVA程序设计与案例M.北京:高等教育出版社,2006.附录源程序主要类和方法简列如下:*LunarCalendarjava*Star制作*/主类publicclassLunarCaIendarextendsJFrameimplementsActionListenerJtemListener构造器,提供初始化等信息publicLunarCalendar(Stringtitle)将当前时间信息保存到SySNoWTime口publicvoidgetSysDate()将万年历要显示的信息保存到sysRunTimepublicvoidgetSysRunDate()响应按钮事件及其方法publicvoidactionPerformed(ActionEventae)响应下拉表选择事件及其方法publicvoiditemStateChanged(ItemEventaa)返回一个整数值,用于寻找StringMonthCn数组中对应的中文月份publicintturnMonth(Stringmonth)/给gregorianCalendar设置信息,主要为了返回初始星期,所以date为1publicvoidsetSysDate(intyear,intmonth)/将显示日期的标签内容初始化为空publicstaticvoidsetDateNull()返回所选年月的天数publicintgetMonthDays(intyear,intmonth)获取月组合框中的整数值publicstaticintgetComboMonth()系统日期中的星期返回当月中的1号是从星期几开始publicintgetInitWeek(StringinitWeek)返回当前年份publicintgetNowYear()返回当前月份publicintgetNowMonth()返回当前日期publicintgetNowDay()获取组合框中应该显示的年份publicintgetShowYear()获取在组合框中显示的中文格式月份:如七月八月等publicintgetShowMonth()显示并刷新系统时间的类classTimerListenerimplementsActionListenerf传回农历y年的总天数finalprivatestaticint!YearDays(inty)传回农历y年闰月的天数finalprivatestaticintleapDays(inty)传回农历y年闰哪个月1-12,没闰传OfinalprivatestaticintleapMonth(inty)传回农历y年m月的总天数finalprivatestaticintmonthDays(inty,intm)传出y年m月d日对应的农历finalpublicstaticlongcalElement(inty,intm,intd)将数字显示的农历日期转换为中文格式publicfinalstaticStringgetChinaDate(intday)/响应下拉表查询功能的方法刷新万年历的显示publicvoidSetChangeDateO与SetChangeDate功能类似,但这只显示今天的信息,主要为了响应“今天”按钮事件,在程序启动时也需调用publicvoidsetNowDate()主要方法,设置阳历、农历、节气、节日都在这里刷新显示必用publicvoidsetLunarDays(intmonthDays,intinitWeek,intday)主方法publicstaticvoidmain(Stringargs)