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 }