万年历实训报告.docx
《万年历实训报告.docx》由会员分享,可在线阅读,更多相关《万年历实训报告.docx(44页珍藏版)》请在冰豆网上搜索。
万年历实训报告
实训报告
桌面万年历设计与开发
满凤环
专业名称:
数字媒体技术
班级:
数字媒体技术10级
学号:
201001051321
信息科学与工程学院
二零一二年十二月
1.概述..................................................3
2.相关技术...............................................3
2.1WindowsAPI函数....................................3
2.2Win32消息体制......................................4
3.总体设计与详细设计.....................................4
3.1系统模块划分........................................5
3.2主要功能模块.......................................6
4.编码实现..............................................6
4.1Main.c.............................................6
4.2ClockDlg.c.........................................24
4.3CalendarDlg.c......................................29
5.实训中遇到的主要问题及解决方法........................31
6.实训体会..............................................32
1.概述【一级标题,黑体,四号,加粗,顶头】
运行桌面万年历程序,可以使时钟显示在Windows的桌面上,右击时钟图标可以在下拉列表中选择万年历显示在桌面上。
时钟具有当前时间、星期、农历和公历日期、生肖年以及地支年显示等功能,另外,在时钟的下拉列表下还有整点报时、更换底色等功能;日历也可以实现很多功能,例如:
显示当前日期,各个月份的农历和公历日期及其传统节日,各个年份相应日期的查询,播放音乐,更换主题等功能。
2.相关技术
2.1WindowsAPI函数
从事Windows应用程序开发,离不开对Win32API函数的调用。
这些函数是WINDOWS提供给应用程序与操作系统的接口,他们犹如“积木块”一样,可以搭建出各种界面丰富,功能灵活的应用程序。
所以可以认为API函数是构筑整个WINDOWS框架的基石,只有充分理解和利用API函数,才能深入到Windows的内部,充分体现系统提供的强大功能和灵活性。
本次的程序运用了一些API函数,例如:
函数
功能
SetTimer()
创建定时器
GetLocalTime()
获得当前时间
SetTextColor()
设置要绘制的文字颜色
TextOut()
该函数用当前选择的字体、背景颜色和正文颜色将一个字符串写到指定位置。
CreatSolidBrush()
创建刷子
CreateFont()
该函数创建一种有特殊性的逻辑字体,此逻辑字体可以在后面被任何设备选择。
SelectObject()
该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
BitBlt()
该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境。
SetRect()
设置指定矩形的内容
SetTextColor()
函数用来设置要绘制的文体颜色。
可以将表格当中的文字设置为一些特殊的颜色。
wsprintf()
整数转换为字符串,宽字符,用Unicode码
LoadImage()
该函数装载图标,光标,或位图。
FillRect()
是指该函数用指定的画刷填充矩形
2.2Win32消息机制
Windows操作系统最大的特点就是其图形化的操作界面,其图形化界面是建立在其消息处理机制这个基础之上的。
如果不理解Windows消息处理机制,肯定无法深入的理解Windows编程。
Windows消息分为系统消息和用户自定义消息,可分为标准windows消息、命令消息和通知消息。
根据已给样本的提示,绘制了日历的圆角矩形背景,并且根据公历日期转换为农历日期的原理来计算出农历,并在日历上标注了一些重要节日,像“春节、元宵节、清明节、端午节、中秋节”等一些重要的农历节日,并且将节假日的字体颜色设置为紫红色;以及“元旦、劳动节、儿童节、教师节、国庆节等阳历节日,并且将节假日的字体颜色也设置为紫红色,然后又写了获取当前系统本机时间的函数,成功的获得了当前本机的时间。
通过一些命令按钮的设置,实现了时钟皮肤,日历背景皮肤的选择改变,时间的查找等。
3.总体设计与详细设计
总体设计:
(1)调用判断是不是闰年的函数。
(2)根据公历日期获得农历日期。
(3)利用泰勒公式由公历日期计算星期。
(4)利用公历日期计算该年的天干地支及生肖等。
(5)在钟表上获得当前本地的系统时间与日期等的显示。
(6)在日历上获得每年每月的日期等的信息并显示。
详细设计:
1、首先绘制日历的圆角矩形背景,用CreateSolidBrush()函数做出矩形的背景颜色,还有CreateRoundRectRgn()函数实现圆角矩形,在日历的右上端和右下端分别输出阳历的当前年月份,及阴历的天干地支年等。
也输出了当年的生肖和生肖图片。
2、判断农历的每月有多少天,调用判断是否为闰年的函数,若为闰年,则定义二月为29天,通过一switch函数输出十二个月的天数。
3、利用SelectObject(),TextOut(),wsprintf()等函数写入标题(设置不同颜色),利用MoveToEx()和LineTo()函数画出日历表的标题框并填充颜色。
4、调用公历转为农历的函数并用for循环获得每日的农历日期,并调CreateSolidBrush(函数标出当天的日期,该日期显示框填充为不同的颜色。
还有节日的标注。
5、对日历上的几个按钮进行设置,使得当年月份发生改变时,日历表可以正常显示。
6、日历表背景的更换,运用了LoadImage(),SelectObject()等函数实现。
7、获得本地系统时间,在表盘上的正确位置输出当天的年月日(调用CreateFont函数按角度输出)及当地时间和星期,公历和阳历均显示,还输出了天干地支和生肖。
8、扩展功能增加了皮肤设置和整点报时功能。
3.1系统模块划分
主界面子系统负责程序主界面的显示、程序主逻辑的控制、以及其他子系统的调用。
分为以下模块:
程序入口模块、消息处理模块、时间处理模块、界面贴图模块。
下图是模块之间的关系图。
其中,程序入口模块,是Windows程序的入口函数,在该模块内创建主界面。
消息处理模块负责响应用户的鼠标和键盘操作。
时间处理模块负责时间运算和显示。
界面贴图模块负责主界面的图像显示。
以下是各模块的详细说明:
模块名称
模块功能
输入
输出
其他说明
程序入口模块
在该模块内创建主界面
Windows调用
主界面创建;定时器安装
Windows程序的入口函数
消息处理模块
负责响应用户的鼠标和键盘操作
用户和键盘鼠标输,Windows其他事件
消息处理
Windows程序的窗口函数
时间处理模块
负责时间运算和显示
定时器间隔
时间
Windows程序的定时器回调函数
界面贴图模块
负责主界面的图像显示
位图
位图显示
无
3.2主要功能模块
4.编码实现
4.1Main.c
#include
#include
#include"resource.h"
#pragmacomment(lib,"WinLib.lib")
voidSetDlgMenuID(UINTnMainDlgID,UINTnCalendarDlgID,UINTnMenuID);
voidSetButtonID(UINTnCalendarID,UINTnExitID,UINTnblueID,UINTnyellowID,UINTngreenID,UINTnpurpleID);
INT_PTRShowMainDlg();
/*
*********************************************************
API函数参考:
GetLocalTime:
获得当前时间(公历:
年、月、日、周)
MoveToEx:
移动划线的起点
LineTo:
绘制到某一点
SetTextColor:
设置要绘制的文字颜色
TextOut:
绘制文字
SetBkMode:
设置背景显示模式
wsprintf:
整数转换为字符串,宽字符,用Unicode码
GetClientRect:
获取窗口大小
GetDC:
获取内存设备
SetTimer:
设置定时器
FillRect:
填充矩形
CreateSolidBrush:
创建刷子
RGB:
设置RGB颜色
CreateFont:
创建一种有特殊性的字体
结构体类型参考:
SYSTEMTIME:
描述时间类型,包括年月日、时分秒、周
*********************************************************
*/
HINSTANCEg_hInst;//保存操作系统传递进来的"应用程序实例句柄",全局变量
//Windows程序入口函数
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnShowCmd)
{
g_hInst=hInstance;//应用程序实例句柄被赋值为一个应用程序的实例句柄
SetDlgMenuID(IDD_DLG_CLOCK,IDD_DLG_CALENDAR,IDR_MENU);
SetButtonID(ID_CALENDAR,ID_EXIT,ID_blue,ID_yellow,ID_green,ID_purple);
ShowMainDlg(IDD_DLG_CLOCK);
}
typedefstruct_stDateTime//定义日期结构体
{
intnYear;
intnMonth;
intnDay;
}stDateTime;//定义日期结构体变量
//定义表格,存储年-2099年的农历信息:
每年的大小月、闰月信息、春节所在的公历日期,用十六进制存储的
unsignedintLunarCalendarTable[199]=
{
0x04AE53,0x0A5748,0x5526BD,0x0D2650,0x0D9544,0x46AAB9,0x056A4D,0x09AD42,0x24AEB6,0x04AE4A,/*1901-1910*/
0x6A4DBE,0x0A4D52,0x0D2546,0x5D52BA,0x0B544E,0x0D6A43,0x296D37,0x095B4B,0x749BC1,0x049754,/*1911-1920*/
0x0A4B48,0x5B25BC,0x06A550,0x06D445,0x4ADAB8,0x02B64D,0x095742,0x2497B7,0x04974A,0x664B3E,/*1921-1930*/
0x0D4A51,0x0EA546,0x56D4BA,0x05AD4E,0x02B644,0x393738,0x092E4B,0x7C96BF,0x0C9553,0x0D4A48,/*1931-1940*/
0x6DA53B,0x0B554F,0x056A45,0x4AADB9,0x025D4D,0x092D42,0x2C95B6,0x0A954A,0x7B4ABD,0x06CA51,/*1941-1950*/
0x0B5546,0x555ABB,0x04DA4E,0x0A5B43,0x352BB8,0x052B4C,0x8A953F,0x0E9552,0x06AA48,0x6AD53C,/*1951-1960*/
0x0AB54F,0x04B645,0x4A5739,0x0A574D,0x052642,0x3E9335,0x0D9549,0x75AABE,0x056A51,0x096D46,/*1961-1970*/
0x54AEBB,0x04AD4F,0x0A4D43,0x4D26B7,0x0D254B,0x8D52BF,0x0B5452,0x0B6A47,0x696D3C,0x095B50,/*1971-1980*/
0x049B45,0x4A4BB9,0x0A4B4D,0xAB25C2,0x06A554,0x06D449,0x6ADA3D,0x0AB651,0x093746,0x5497BB,/*1981-1990*/
0x04974F,0x064B44,0x36A537,0x0EA54A,0x86B2BF,0x05AC53,0x0AB647,0x5936BC,0x092E50,0x0C9645,/*1991-2000*/
0x4D4AB8,0x0D4A4C,0x0DA541,0x25AAB6,0x056A49,0x7AADBD,0x025D52,0x092D47,0x5C95BA,0x0A954E,/*2001-2010*/
0x0B4A43,0x4B5537,0x0AD54A,0x955ABF,0x04BA53,0x0A5B48,0x652BBC,0x052B50,0x0A9345,0x474AB9,/*2011-2020*/
0x06AA4C,0x0AD541,0x24DAB6,0x04B64A,0x69573D,0x0A4E51,0x0D2646,0x5E933A,0x0D534D,0x05AA43,/*2021-2030*/
0x36B537,0x096D4B,0xB4AEBF,0x04AD53,0x0A4D48,0x6D25BC,0x0D254F,0x0D5244,0x5DAA38,0x0B5A4C,/*2031-2040*/
0x056D41,0x24ADB6,0x049B4A,0x7A4BBE,0x0A4B51,0x0AA546,0x5B52BA,0x06D24E,0x0ADA42,0x355B37,/*2041-2050*/
0x09374B,0x8497C1,0x049753,0x064B48,0x66A53C,0x0EA54F,0x06B244,0x4AB638,0x0AAE4C,0x092E42,/*2051-2060*/
0x3C9735,0x0C9649,0x7D4ABD,0x0D4A51,0x0DA545,0x55AABA,0x056A4E,0x0A6D43,0x452EB7,0x052D4B,/*2061-2070*/
0x8A95BF,0x0A9553,0x0B4A47,0x6B553B,0x0AD54F,0x055A45,0x4A5D38,0x0A5B4C,0x052B42,0x3A93B6,/*2071-2080*/
0x069349,0x7729BD,0x06AA51,0x0AD546,0x54DABA,0x04B64E,0x0A5743,0x452738,0x0D264A,0x8E933E,/*2081-2090*/
0x0D5252,0x0DAA47,0x66B53B,0x056D4F,0x04AE45,0x4A4EB9,0x0A4D4C,0x0D1541,0x2D92B5/*2091-2099*/
};
//定义天干地支表,年的数据
char*TianGanDizhi[60]=
{
"甲子","乙丑","丙寅","丁卯","戊辰","已巳","庚午","辛未","壬申","癸酉",
"甲戌","乙亥","丙子","丁丑","戊寅","已卯","庚辰","辛巳","壬午","癸未",
"甲申","乙酉","丙戌","丁亥","戊子","已丑","庚寅","辛卯","壬辰","癸巳",
"甲午","乙未","丙申","丁酉","戊戌","已亥","庚子","辛丑","壬寅","癸卯",
"甲辰","乙巳","丙午","丁未","戊申","已酉","庚戌","辛亥","壬子","癸丑",
"甲寅","乙卯","丙辰","丁巳","戊午","已未","庚申","辛酉","壬戌","癸亥"
};
//定义一个月中的农历天数据
char*ChDayTable[]=
{
"*","初一","初二","初三","初四","初五",
"初六","初七","初八","初九","初十",
"十一","十二","十三","十四","十五",
"十六","十七","十八","十九","二十",
"廿一","廿二","廿三","廿四","廿五",
"廿六","廿七","廿八","廿九","三十"
};
//定义一年中的农历月数据
char*ChMonthTable[]={"*","正","二","三","四","五","六","七","八","九","十","十一","腊"};
char*shengxiao[]={"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};
//定义表格,存储阳历每月日离元旦的天数(不考虑闰年)
unsignedintMonthAdd[12]={0,31,59,90,120,151,181,212,243,273,304,334};
//定义用户要显示的年、月、日
unsignedintnCurrentYear=0;
unsignedintnCurrentMonth=0;
unsignedintnCurrentDay=0;
UINTSONG=0,ON=0;//控制音乐
//————————判断某年是否为公历闰年————————//
intIsLeapYear(WORDYear){
if(Year%100==0)
{if(Year%400==0)
return1;}
elseif(Year%4==0)
return1;
}
//————————公历日期转农历日期的函数————————//
voidSunToLunar(conststDateTime*pSunDay,stDateTime*pLunarDay)
{
inti=0;
intSunDiff=0;
intSpringDiff=0;
intnSpringYear=pSunDay->nYear;
intnSpringMonth=1;
intnSpringDay=0;
//计算当前公历日离当年元旦的天数
SunDiff=MonthAdd[pSunDay->nMonth-1]+pSunDay->nDay-1;
if(IsLeapYear(pSunDay->nYear)&&(pSunDay->nMonth>2))//若是闰年且大于月,天数再加
SunDiff++;
//计算春节所在公历日离元旦的天数:
通过查表,计算当年的春节所在的公历日期
if(((LunarCalendarTable[pSunDay->nYear-1901]&0x60)>>5)==1)//若春节在公历月
SpringDiff=(LunarCalendarTable[pSunDay->nYear-1901]&0x1F)-1;
else//若春节在公历月
SpringDiff=(LunarCalendarTable[pSunDay->nYear-1901]&0x1F)-1+31;
//SunDiff和SpringDiff的差就是当前公历日离春节的天数
if(SunDiff>=SpringDiff)//公历日在春节后
{
intx=SunDiff-SpringDiff;
intbLunar=(LunarCalendarTable[nSpringYear-1901]&0xF00000)>>20;//闰月月份
i=0;
nSpringMonth=1;
for(;;)
{
inta=(LunarCalendarTable[pSunDay->nYear-1901]&(0x80000>>i));//计算大小月
if(a==0)
a=29;
else
a=30;
if(xbreak;
x=x-a;
i++;
nSpringMonth++;
}
nSpringDay=x+1;
//如果有闰月
if(nSpringMonth>bLunar&&bLunar>0)
nSpringMonth--;
}
else//公历日在春节前
{
intx=SpringDiff-SunDiff;
intnShift=0;
intbLunar=(LunarCalendarTable[nSpringYear-1901]&0xF00000)>>20;//闰月月份
i=0;
nSpringYear--;//需要上一年的农历信息
nSpringMonth=12;//从最后一个月开始计算
if(bLunar==0)//如果没有闰月
nShift=0x100;
else
nShift=0x80;
for(;;)
{
inta=(LunarCalendarTable[nSpringYear-1901]&(nShift<
if(a==0)
a=29;
else
a=30;
if(x{
x=a-x;
break;
}
x=x-a;
i++;
nSpringMonth--;
}
nSpringDay=x+1;
if(nSpringMonth0)
nSpringMonth++;
}
pLunarDay->nYear=nSpringYear;
pLunarDay->nMonth=nSpringMonth;
pLunarDay->nDay=nSpringDay;
}
//————————根据公历日期获得星期————————//
intGetDayOfWeek(conststDateTime*pSunDay)
{
//根据泰勒公式
//nWeek