1、北邮程序设计实践实验一时钟改进实验报告程序设计实践实验一:绘图程序Draw的实现之时钟改进设计报告 课题名称: 时钟改进之星轨与时钟学生姓名: 班 级: 班内序号: 学 号: 日 期: 一、课题概述二、系统设计三、程序设计亮点展示 四、 运行结果分析五、遇到的难题与解决方法 六、总结参考文献一、课题概述 1.1课题目标和主要内容主要内容:根据所提供的时钟代码,新建派生类,利用WINDOWS AP设计和绘制图形。目标:以培养学生动手实践能力为目的,重点是在学习C+程序设计和数据结构的基础上,使学生从实践中学习如何综合运用C+和数据结构的相关知识解决实际应用中的问题,了解程序设计的基本思想在具体实
2、际应用中的体现,掌握分析问题、解决问题的方法,从而提高学生的编程能力,达到编程熟练、会调试、代码书写规范的基本要求,具备简单应用程序的设计、实现能力。平台:Visual studio 2013 API平台。 1.2系统的主要功能1.绘制菜单一:绘制星轨时钟,准确读出系统时间,时分秒钟都为新建图元类,代表星星,月亮,阳光;2.绘制菜单二:绘制成长星轨,可以看到随时间变化、成长、旋转的星星 ;2. 系统设计 2.1 系统总体框架 2.2 系统详细设计1 类关系图及描述 2 程序流程图及描述 指定窗口函数(消息处理入口)添加菜单资源初始化窗口生成窗口并显示更新窗口UpdateWindow(hwnd)
3、;若UpdateRegion不空,则发送WM_PAINT消息while (GetMessage(&msg, NULL, 0, 0)消息循环,对用户操作进行响应TranslateMessage(&msg); 将虚拟键消息转换成字符消息,再送入消息队列DispatchMessage(&msg); 分发消息,将队列中消息发送到窗口处理函数窗口过程函数绘图函数 2.3 关键算法分析 算法1:窗口过程函数1 算法功能当按下指定菜单,窗口需要运行相应的处理函数。 2 算法基本思想 在API里定义了一个函数为回调函数,当系统需要向窗口发送消息时,就会调用窗口给出的回调函数WindowProc,如果Windo
4、wProc函数不处理这个消息,就可以把它转向DefWindowProc函数来处理,这是系统的默认消息处理函数。3源代码LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 函数: WndProc(HWND, UINT, WPARAM, LPARAM)/ 目的: 处理主窗口的消息。/ WM_COMMAND - 处理应用程序菜单/ WM_PAINT - 绘制主窗口/ WM_DESTROY - 发送退出消息并返回/LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LP
5、ARAM lParam) static int menuId=0; int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; HDC mainwin_hdc; switch (message) case WM_CREATE: SetTimer(hWnd,1,1000,NULL); break; case WM_TIMER: InvalidateRect(hWnd,NULL,TRUE); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); switch (wmId) cas
6、e IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_FIG1: menuId=IDM_FIG1; InvalidateRect(hWnd,NULL,TRUE); break; case IDM_FIG2: menuId=IDM_FIG2; InvalidateRect(hWnd,NULL,TRUE); break; case IDM_FIG3: menuId=IDM_FIG3; InvalidateRect(hWnd,NULL,TRUE); break; case
7、IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; case WM_PAINT: mainwin_hdc = BeginPaint(hWnd, &ps); if (menuId) cwin.open(hWnd, mainwin_hdc); ccc_win_main(menuId); EndPaint(hWnd, &ps); break; case WM_DESTROY: KillTimer(hWnd,1); PostQuitMessa
8、ge(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); return 0; 算法2:绘图函数(以画ellipse为例)1 算法功能 运行函数时,绘出相应图形。2 算法基本思想设置double x, double y, double ra, double rb,COLORREF mColor等变量,当运行函数时根据相应参数画出图形在这里我新建了一个重载函数和类,多定义了COLORREF icolor变量。oColor指的是画圆的笔的颜色,而icolor则是填充圆的画刷的颜色。通过在void Graph
9、icWindow:ellipse中新建笔和刷子用来绘图,最后将比和刷子的颜色恢复成预制,删除新建笔刷。如下图所示:3源代码 /* Plots a ellipse. */ void ellipse(double x, double y, double ra, double rb,COLORREF mColor); void ellipse(double x, double y, double ra, double rb, COLORREF oColor,COLORREF icolor);void GraphicWindow:ellipse(double x, double y, double r
10、a, double rb, COLORREF oColor,COLORREF icolor) HPEN save_pen=(HPEN)SelectObject(_hdc, CreatePen(PS_SOLID, 1, oColor); HBRUSH brush = CreateSolidBrush(icolor); HBRUSH save_brush=(HBRUSH)SelectObject(_hdc,brush); Ellipse(_hdc, user_to_disp_x(x - ra), user_to_disp_y(y - rb), user_to_disp_x(x + ra), use
11、r_to_disp_y(y + rb); SelectObject(_hdc, save_brush); DeleteObject(brush); SelectObject(_hdc,save_pen);GraphicWindow& GraphicWindow:operatorSetColor(RGB(148, 0, 211);/ 深紫罗兰色 clkPlate3.SetColoro(RGB(148, 0, 211); cwin clkPlate3; 其他 使用了尽量减少值传递,多用引用来传递参数有助于提高代码简洁和效率的方法。三、程序设计亮点展示亮点一:新建三个图元类starsline,moo
12、nmline以及sunhline来画新的表针新建三个图元类starsline,moonmline以及sunhline来画新的表针,表针端头都有随之转动的特殊图像如图所示: sunhline Starsline moonmline以starsline为例,实现代码如下 /* Plots a starsline. */ void Starsline(double xfrom, double yfrom, double xto, double yto,COLORREF mColor);class starsline:public Shape public: starsline(); starslin
13、e(Point p1, Point p2); Point get_start() const; Point get_end() const; COLORREF get_color() const; virtual void move(double dx, double dy); virtual void SetColor(COLORREF mColor);private: Point from; Point to; COLORREF color;starsline:starsline()starsline:starsline(Point p1, Point p2) from = p1, to
14、= p2;Point starsline:get_start() const return from;Point starsline:get_end() const return to;COLORREF starsline:get_color() const return color;void starsline:move(double dx, double dy) from.move(dx, dy); to.move(dx, dy);void starsline:SetColor(COLORREF mColor) color=mColor;void GraphicWindow:Starsli
15、ne(double xfrom, double yfrom, double xto, double yto, COLORREF mColor) double c=(yfrom-yto)/sqrt(xfrom-xto)*(xfrom-xto)+(yfrom-yto)*(yfrom-yto); double p=acos(c); double x6,y6; for (int i = 0; i 6; i+) xi=0.7*sin(p+i*PI/3)+xto;/利用弧度定义六芒星的六个顶点 yi=0.7*cos(p+i*PI/3)+yto; SelectObject(_hdc, CreatePen(P
16、S_SOLID, 1,mColor);/设置画笔,用笔分别连接六芒星对应顶点画出星星 MoveToEx(_hdc, user_to_disp_x(xfrom), user_to_disp_y(yfrom), 0); LineTo(_hdc,user_to_disp_x(xto), user_to_disp_y(yto); MoveToEx(_hdc,user_to_disp_x(x0) , user_to_disp_y(y0), 0); LineTo(_hdc,user_to_disp_x(x2),user_to_disp_y(y2); MoveToEx(_hdc,user_to_disp_x
17、(x2) , user_to_disp_y(y2), 0); LineTo(_hdc,user_to_disp_x(x4),user_to_disp_y(y4); MoveToEx(_hdc,user_to_disp_x(x4) , user_to_disp_y(y4), 0); LineTo(_hdc,user_to_disp_x(x0),user_to_disp_y(y0); MoveToEx(_hdc,user_to_disp_x(x1) , user_to_disp_y(y1), 0); LineTo(_hdc,user_to_disp_x(x3),user_to_disp_y(y3)
18、; MoveToEx(_hdc,user_to_disp_x(x3) , user_to_disp_y(y3), 0); LineTo(_hdc,user_to_disp_x(x5),user_to_disp_y(y5); MoveToEx(_hdc,user_to_disp_x(x5) , user_to_disp_y(y5), 0); LineTo(_hdc,user_to_disp_x(x1),user_to_disp_y(y1); GraphicWindow& GraphicWindow:operator(starsline a) Starsline(a.get_start().get
19、_x(), a.get_start().get_y(), a.get_end().get_x(), a.get_end().get_y(),a.get_color(); return *this;starsline sLine(org, sEnd); sLine.SetColor(RGB(255, 255, 255); moonmline mLine(org, mEnd); sunhline hLine(org, hEnd); hLine.SetColor(RGB(255, 255, 255); cwinhLinemLinesLine;亮点二:利用弧度绘制六芒星通过一个循环找到围绕指针端点等间
20、隔分布的六个点,再调用系统函数连线。围绕夜空转动的五彩星星则是调用了系统时间来改变星星的位置和色彩 实现代码如下:double c = (yfrom - yto) / sqrt(xfrom - xto)*(xfrom - xto) + (yfrom - yto)*(yfrom - yto); double p = acos(c); double x4, y4; for (int i = 0; i 4; i+) xi = 0.7*sin(p + i*PI / 2) + xto;/利用弧度定义 yi = 0.7*cos(p + i*PI / 2) + yto; MoveToEx(_hdc, use
21、r_to_disp_x(x0), user_to_disp_y(y0), 0); LineTo(_hdc, user_to_disp_x(x1), user_to_disp_y(y1); MoveToEx(_hdc, user_to_disp_x(x1), user_to_disp_y(y1), 0); LineTo(_hdc, user_to_disp_x(x2), user_to_disp_y(y2); MoveToEx(_hdc, user_to_disp_x(x2), user_to_disp_y(y2), 0); LineTo(_hdc, user_to_disp_x(x3), us
22、er_to_disp_y(y3); MoveToEx(_hdc, user_to_disp_x(x3), user_to_disp_y(y3), 0); LineTo(_hdc, user_to_disp_x(x0), user_to_disp_y(y0); MoveToEx(_hdc, user_to_disp_x(x1), user_to_disp_y(y1), 0); LineTo(_hdc, user_to_disp_x(x3), user_to_disp_y(y3); MoveToEx(_hdc, user_to_disp_x(x0), user_to_disp_y(y0), 0);
23、 LineTo(_hdc, user_to_disp_x(x2), user_to_disp_y(y2);亮点三:利用系统时间绘制围绕表盘缩进的星光/调用系统时间,利用point类在表盘里面画星轨 radius=6-local.tm_sec%6; for(i=0;iSetColor(RGB(255,255,255); cwinmPoint; 亮点四:利用系统时间和Point,Line,Starsline类绘制变化的星轨 /画星星 Point org(0, 0); double x8, y8; double l; l = 9 - local.tm_sec % 9; x0 = 0; y0 = l;
24、 for (int i = 1; i 8; i+) xi = l*sin(/*PI / 2 +*/ i*PI / 4); /利用弧度定义六芒星的六个顶点 yi = l*cos(/*PI/2*/ i*PI / 4) ; 其中l是随时间以9为周期变化的数值,然后再调用相应的类绘图四、 运行结果分析运行效果:XQY的绘图设计菜单栏一:【月黑见渔灯,孤光一点萤】星轨时钟时钟调用了系统时间,分针秒针时针分别指向对应的位置,秒针尽头一颗六芒星随之转动,分针尽头一轮弯月随之转动,时针尽头则是一个小小的铅垂牵引着它。同时,在渐变的紫色调表盘上有均匀分布的星光,随时间一圈一圈闪现在不同颜色的表盘上。浅紫色的夜空
25、背景下,还有一颗颜色按七原色赤橙黄绿青蓝紫变化的星星围绕表盘转动。XQY的绘图设计菜单栏二:【微微风簇浪,散作满河星】成长星轨夜空背景下,一颗象牙白的多角星星正在一步一步绽放她的光芒,时间每过去一秒,这个星星就要彻底地变化一次形状。而每一个角的顶点,又幻化成无数小小六芒星。一颗五彩的星星围绕成长的星轨转动 五、遇到的难题与解决方法难题一:如何填充渐变表盘的颜色?解决方式是在ellipse函数中预置一个笔刷,就可以根据颜色填充了,不过要注意最后要让笔刷复位难题二:如何画出随时间变化的星光?见亮点三难题三:如何画弧线图类月亮?上网搜索后找到画弧线的系统函数Arc,根据端点坐标计算出所需参数即可难题
26、四:如何使动态星星的颜色发生周期性变化?利用if else语句判断时间与7取余的值,每次设置一个不同颜色六、总结本次课题相对上次的课题难度加大不少,特别是要运用以前从未接触的Windows API平台,还需要复习大一学习的c+内容,查阅不少资料。在同学们一次又一次的讨论摸索下,渐渐摸索出来了一步有一步。 通过这次API的编程,让我又学会了一种新的编译办法。相比之下,觉得API界面比控制台界面更加美观大方。在学习编程过程中,锻炼了自己独立思考和解决问题的能力得,也会影响到以后各科的学习,甚至是终生有益。五、参考文献1徐惠民等,C+高级语言程序设计案例与实践辅导,北京:人民邮电出版社,20122徐雅静等,数据结构与stl,北京:北京邮电大学,20113徐惠名等,C+高级语言程序设计,北京,人民邮电出版社,2012