Windows下编程--模拟时钟的实现

时间:2022-06-09
本文章向大家介绍Windows下编程--模拟时钟的实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

windows下编程--模拟时钟的实现:

主要可以分为几个步骤:

(1)   编写按键事件处理(启动和停止时钟)

(2)   编写时钟事件处理,调用显示时钟函数

(3)   编写显示时钟函数,要调用显示数字时钟函数、画出钟面函数和画出指针函数

(4)   编写显示数字时钟函数。注意要自己用矩形填充(FillRect)擦除背景。

(5)   编写画出钟面函数

(6)   编写画出指针函数

(7)   增加WM_PAINT消息处理:调用显示时钟函数,防止在停止时钟后从窗口最小化恢复会不显示内容。

最后结果类似于这种形式---一个模拟时钟,数字时钟+画面时钟

每一步的说明:

(1)编写按键事件处理(启动和停止时钟)

(2)   编写时钟事件处理,调用显示时钟函数

(3)   编写显示时钟函数,要调用显示数字时钟函数、画出钟面函数和画出指针函数

(4)   编写显示数字时钟函数。注意要自己用矩形填充(FillRect)擦除背景。

(5) 编写画出钟面函数

(6)   编写画出指针函数(注意好时针分针秒针的角度关系计算方法就行了)

(7)   增加WM_PAINT消息处理:调用显示时钟函数,防止在停止时钟后从窗口最小化恢复会不显示内容。

基本上只是考察了基本的windows编程,掌握好时钟事件和按钮的编程。

最后附上长长的代码...

  1 /*------------------------------------------------------------
  2    HELLOWIN.C -- Displays "Hello, Windows 98!" in client area
  3                  (c) Charles Petzold, 1998
  4   ------------------------------------------------------------*/
  5 
  6 #include <windows.h>
  7 #include <stdio.h>
  8 #include <math.h>
  9 
 10 #define PI        3.14159265358979323846
 11 #define TIMER_SEC   1
 12 #define TIMER_MIN   2
 13 #define BUTTON1     3
 14 #define BUTTON2     4
 15 
 16 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 17 
 18 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
 19                     PSTR szCmdLine, int iCmdShow)
 20 {
 21      static TCHAR szAppName[] = TEXT ("HelloWin") ;
 22      HWND         hwnd,hwndButton1,hwndButton2;
 23      MSG          msg ;
 24      WNDCLASS     wndclass ;
 25 
 26      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
 27      wndclass.lpfnWndProc   = WndProc ;
 28      wndclass.cbClsExtra    = 0 ;
 29      wndclass.cbWndExtra    = 0 ;
 30      wndclass.hInstance     = hInstance ;
 31      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
 32      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
 33      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 34      wndclass.lpszMenuName  = NULL ;
 35      wndclass.lpszClassName = szAppName ;
 36 
 37      if (!RegisterClass (&wndclass))
 38      {
 39           MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
 40                       szAppName, MB_ICONERROR) ;
 41           return 0 ;
 42      }
 43      
 44      hwnd = CreateWindow (szAppName,                  // window class name
 45                           TEXT ("Analog Clock"), // window caption
 46                           WS_OVERLAPPEDWINDOW,        // window style
 47                           CW_USEDEFAULT,              // initial x position
 48                           CW_USEDEFAULT,              // initial y position
 49                           560,              // initial x size
 50                           360,              // initial y size
 51                           NULL,                       // parent window handle
 52                           NULL,                       // window menu handle
 53                           hInstance,                  // program instance handle
 54                           NULL) ;                     // creation parameters
 55      
 56      ShowWindow (hwnd, iCmdShow) ;
 57      UpdateWindow (hwnd) ;
 58 
 59      hwndButton1 = CreateWindow(TEXT("button"),                       // 窗口类名(系统内部定义了该窗口类)
 60          TEXT("StartTimer"),                               // 标题
 61          WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,        // 样式
 62          100, 250,                                      // 左上角位置x,y
 63          120, 40,                                         // 宽度,高度
 64          hwnd,                                        // 父窗口句柄
 65          (HMENU)BUTTON1,                                // 控件ID
 66          hInstance,                                     // 实例句柄
 67          NULL);                                        // 自定义参数
 68 
 69      hwndButton2 = CreateWindow(TEXT("button"),                       // 窗口类名
 70          TEXT("StopTimer"),                               // 标题
 71          WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,        // 样式
 72          300, 250,                                      // 左上角位置x,y
 73          120, 40,                                         // 宽度,高度
 74          hwnd,                                        // 父窗口句柄
 75          (HMENU)BUTTON2,                                // 控件ID
 76          hInstance,                                     // 实例句柄
 77          NULL);
 78 
 79      while (GetMessage (&msg, NULL, 0, 0))
 80      {
 81           TranslateMessage (&msg) ;
 82           DispatchMessage (&msg) ;
 83      }
 84      return msg.wParam ;
 85 }
 86 
 87 // 画出钟面(不包括指针)
 88 void DrawClockFace(HDC hdc){
 89 //    PAINTSTRUCT ps;
 90     RECT        rect;
 91     HPEN hPen;
 92     HPEN oldPen;
 93     hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));                    // 创建画笔(线形,线宽,颜色)
 94     oldPen = (HPEN)SelectObject(hdc, hPen);        // 选择画笔,并保留原画笔
 95     Ellipse(hdc, 180, 20, 340, 180);   // 时钟--半径 80  作出时钟原始图像
 96     Rectangle(hdc, 220, 205, 295, 230);
 97     double xStart1, yStart1, xEnd1, yEnd1;
 98     for (int i = 0; i <= 11; i++){
 99         if (i <= 3){
100             xEnd1 = 260 + 80 * sin(i* PI / 6);
101             xStart1 = 260 + (80 - 10) * sin(i* PI / 6);
102             yEnd1 = 100 - 80 * cos(i* PI / 6);
103             yStart1 = 100 - (80 - 10) * cos(i* PI / 6);
104         }
105         if (i > 3 && i <= 6){
106             xEnd1 = 260 + 80 * sin(i* PI / 6);
107             xStart1 = 260 + (80 - 10) * sin(i* PI / 6);
108             yStart1 = 100 + (80 - 10) * cos(PI - i* PI / 6);
109             yEnd1 = 100 + 80 * cos(PI - i* PI / 6);
110         }
111         if (i > 6 && i <= 9)
112         {
113             xEnd1 = 260 - 80 * cos(1.5*PI - i* PI / 6);
114             xStart1 = 260 - (80 - 10) * cos(1.5*PI - i* PI / 6);
115             yStart1 = 100 + (80 - 10) * sin(1.5*PI - i* PI / 6);
116             yEnd1 = 100 + 80 * sin(1.5*PI - i* PI / 6);
117         }
118         if (i > 9){
119             xEnd1 = 260 - 80 * sin(2 * PI - i* PI / 6);
120             xStart1 = 260 - (80 - 10) * sin(2 * PI - i* PI / 6);
121             yEnd1 = 100 - 80 * cos(2 * PI - i* PI / 6);
122             yStart1 = 100 - (80 - 10) * cos(2 * PI - i* PI / 6);
123         }
124         MoveToEx(hdc, xStart1, yStart1, NULL);
125         LineTo(hdc, xEnd1, yEnd1);
126     }
127     DeleteObject(hPen);
128     // 钟面相应数字 --- 12
129     rect.left = 250;
130     rect.top = 5;
131     rect.right = 270;
132     rect.bottom = 18;
133     DrawText(hdc, TEXT("12"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
134     // 钟面相应数字 --- 11
135     rect.left = 210;
136     rect.top = 15;
137     rect.right = 220;
138     rect.bottom = 30;
139     DrawText(hdc, TEXT("11"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
140     // 钟面相应数字 --- 10
141     rect.left = 175;
142     rect.top = 50;
143     rect.right = 190;
144     rect.bottom = 60;
145     DrawText(hdc, TEXT("10"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
146     // 钟面相应数字 --- 9
147     rect.left = 165;
148     rect.top = 95;
149     rect.right = 175;
150     rect.bottom = 105;
151     DrawText(hdc, TEXT("9"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
152     // 钟面相应数字 --- 8
153     rect.left = 175;
154     rect.top = 135;
155     rect.right = 190;
156     rect.bottom = 145;
157     DrawText(hdc, TEXT("8"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
158     // 钟面相应数字 --- 7
159     rect.left = 208;
160     rect.top = 167;
161     rect.right = 215;
162     rect.bottom = 185;
163     DrawText(hdc, TEXT("7"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
164     // 钟面相应数字 --- 6
165     rect.left = 250;
166     rect.top = 182;
167     rect.right = 270;
168     rect.bottom = 192;
169     DrawText(hdc, TEXT("6"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
170     // 钟面相应数字 --- 5
171     rect.left = 295;
172     rect.top = 170;
173     rect.right = 310;
174     rect.bottom = 180;
175     DrawText(hdc, TEXT("5"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
176     // 钟面相应数字 --- 4
177     rect.left = 335;
178     rect.top = 135;
179     rect.right = 345;
180     rect.bottom = 145;
181     DrawText(hdc, TEXT("4"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
182     // 钟面相应数字 --- 3
183     rect.left = 345;
184     rect.top = 95;
185     rect.right = 355;
186     rect.bottom = 105;
187     DrawText(hdc, TEXT("3"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
188     // 钟面相应数字 --- 2
189     rect.left = 335;
190     rect.top = 48;
191     rect.right = 345;
192     rect.bottom = 60;
193     DrawText(hdc, TEXT("2"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
194     // 钟面相应数字 --- 1
195     rect.left = 300;
196     rect.top = 20;
197     rect.right = 310;
198     rect.bottom = 30;
199     DrawText(hdc, TEXT("1"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
200     return;
201 }
202 
203 // 画出时钟指针
204 void DrawClockHands(HDC hdc,int hour,int min,int sec){
205     PAINTSTRUCT ps;
206     RECT        rect;
207     HPEN hPen;
208     HPEN oldPen;
209     double xStart1, yStart1, xEnd1, yEnd1;
210     hour = (hour >= 12 ? hour - 12 : hour);
211     hPen = CreatePen(PS_SOLID, 5, RGB(255, 0, 0));                    // 创建画笔(线形,线宽,颜色)
212     oldPen = (HPEN)SelectObject(hdc, hPen);        // 选择画笔,并保留原画笔
213                                            // 显示时针
214     xStart1 = 260;
215     yStart1 = 100;
216     xEnd1 = 260 + (80 - 50) * sin(hour*PI / 6 + ((min * 60 + sec) * PI / (1800*12)));
217     yEnd1 = 100 - (80 - 50) * cos(hour*PI / 6 + ((min * 60 + sec) * PI / (1800*12)));
218     MoveToEx(hdc, xStart1, yStart1, NULL);
219     LineTo(hdc, xEnd1, yEnd1);
220     DeleteObject(hPen);
221 
222     hPen = CreatePen(PS_SOLID, 3, RGB(0, 255, 0));                    // 创建画笔(线形,线宽,颜色)
223     oldPen = (HPEN)SelectObject(hdc, hPen);        // 选择画笔,并保留原画笔
224                                          // 显示分针
225     xStart1 = 260;
226     yStart1 = 100;
227     xEnd1 = 260 + (80 - 35) * sin(min*PI / 30 + (sec * PI / 1800));
228     yEnd1 = 100 - (80 - 35) * cos(min*PI / 30 + (sec * PI / 1800));
229     MoveToEx(hdc, xStart1, yStart1, NULL);
230     LineTo(hdc, xEnd1, yEnd1);
231     DeleteObject(hPen);
232 
233     hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));                    // 创建画笔(线形,线宽,颜色)
234     oldPen = (HPEN)SelectObject(hdc, hPen);        // 选择画笔,并保留原画笔
235                                           // 显示秒针
236     xStart1 = 260;
237     yStart1 = 100;
238     xEnd1 = 260 + (80 - 15) * sin(sec * PI / 30);
239     yEnd1 = 100 - (80 - 15) * cos(sec * PI / 30);
240     MoveToEx(hdc, xStart1, yStart1, NULL);
241     LineTo(hdc, xEnd1, yEnd1);
242     DeleteObject(hPen);
243 
244     return;
245 }
246 /*////////////////////////////////////////////////////
247 void ShowTime1(HDC hdc){          // use for debug
248     HPEN hPen, oldPen;
249     hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));    // 创建画笔(线形,线宽,颜色)
250     oldPen = (HPEN)SelectObject(hdc, hPen);        // 选择画笔,并保留原画笔
251     MoveToEx(hdc, 5, 5, NULL);
252     LineTo(hdc, 10, 10);
253 }
254 *////////////////////////////////////////////////////
255 
256 // 显示数字时钟,注意用函数FillRect擦除背景
257 void ShowTime(HDC hdc,int hour,int min,int sec){
258     PAINTSTRUCT ps;
259     RECT       rect;
260     LOGBRUSH    logbrush;
261     HBRUSH        hBrush, oldBrush;
262     HRGN        hRgn;        // 区域用于区域填充、剪切、合并、反转、画边框或设无效区 
263 
264     HDC hdc1;
265     HPEN hPen, oldPen;
266     hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));                    // 创建画笔(线形,线宽,颜色)
267     oldPen = (HPEN)SelectObject(hdc1, hPen);        // 选择画笔,并保留原画笔
268     MoveToEx(hdc1, 5, 5, NULL);
269     LineTo(hdc1, 10, 10);
270 
271 //    logbrush.lbColor = RGB(255, 255, 255);
272 //    logbrush.lbHatch = HS_BDIAGONAL;                    // 阴影样式:HS_BDIAGONAL 对角线,HS_DIAGCROSS 对角交叉线
273 //    logbrush.lbStyle = BS_HATCHED;                        // 画刷样式:BS_SOLID 实心,BS_HATCHED 阴影
274 //    hBrush = (HBRUSH)CreateBrushIndirect(&logbrush);
275     hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
276     oldBrush = (HBRUSH)SelectObject(hdc, hBrush);        // 选择画刷,并保留原画刷
277     SelectObject(hdc, hBrush);
278     hRgn = CreateEllipticRgn(195, 35, 325, 165);        // 定义区域 
279     FillRgn(hdc, hRgn, hBrush);                            // 填充区域
280     DeleteObject(hBrush);                            // 删除画刷
281     SelectObject(hdc, oldBrush);                    // 恢复原画刷
282 
283     DrawClockHands(hdc, hour, min, sec);
284     return;
285 }
286 
287 // 显示时钟函数,
288 void ShowClock(HWND hwnd){
289     int x,y,r;
290     HDC hdc = GetDC(hwnd);
291     RECT rect;
292     TCHAR buf[100];
293     SYSTEMTIME     st;
294 
295     //GetClientRect(hwnd,&rect);
296     rect.left = 230;
297     rect.top = 210;
298     rect.right = rect.left + 100;
299     rect.bottom = rect.top + 30;
300     GetLocalTime(&st);
301     wsprintf(buf, TEXT("%d:%d:%d"), st.wHour, st.wMinute, st.wSecond);
302     DrawText(hdc, buf, -1, &rect,
303         DT_SINGLELINE | DT_LEFT | DT_TOP);
304 
305     ReleaseDC(hwnd, hdc);
306     return;
307 }
308 
309 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
310 {
311      HDC         hdc ;
312      PAINTSTRUCT ps ;
313      HPEN hPen;
314      HPEN oldPen;
315      SYSTEMTIME     st;
316      switch (message)
317      {
318      case WM_CREATE:
319           PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
320           return 0 ;
321           
322      case WM_PAINT:
323           hdc = BeginPaint (hwnd, &ps) ;
324           DrawClockFace(hdc);   // 画钟
325           GetLocalTime(&st);    //画时针分针秒针
326          DrawClockHands(hdc ,st.wHour, st.wMinute, st.wSecond);
327           ShowClock(hwnd);// 当窗口重刷时显示时间,否则停止时钟时可能空白
328         //  EndPaint(hwnd, &ps) ;
329           return 0 ;
330      
331      case WM_COMMAND:
332          // LOWORD (wParam) 子窗口ID, HIWORD (wParam)     按钮通知码, lParam    子窗口句柄
333 
334          switch (LOWORD(wParam))  //子窗口ID
335          {
336          case BUTTON1:
337              SetTimer(hwnd, TIMER_SEC, 1000, NULL); // 启动定时器(1000毫秒一次),TIMER_SEC为自定义索引号
338              break;
339          case BUTTON2:
340              KillTimer(hwnd, TIMER_SEC);            // 删除定时器
341              break;
342          }
343          return 0;
344 
345      case WM_TIMER:
346          switch (wParam)
347          {
348          case TIMER_SEC:
349              ShowClock(hwnd);//每秒一次的处理
350              InvalidateRgn(hwnd, NULL, 1);     // 使区域无效
351             // ShowTime1(hdc);
352              ShowTime(hdc, st.wHour, st.wMinute, st.wSecond);
353 
354              break;
355          case TIMER_MIN:        //每分钟一次的处理
356              break;
357          }
358          return 0;
359      case WM_DESTROY:
360           PostQuitMessage (0) ;
361           return 0 ;
362      }
363      return DefWindowProc (hwnd, message, wParam, lParam) ;
364 }