一个用Windows SDK实现的时钟

为了更好的熟悉window程序设计,特编写了下面的小示例(参照Windows程序设计第二版),现将程序实现总结如下:

程序运行图:

程序代码如下:

// header files

#include "windows.h"

#include "math.h"

 

 

// defines

#define WINDOW_CLASS_NAME "3D Game"

 

#define IDT_CLOCK   2

#define IDM_TOPMOST 3

#define IDM_HELP    4

 

// global variable for use

HINSTANCE hInstance_app;

HWND      hMainWnd;

 

// variables for timer use //--------------------------------------------------------

 

// 上一次Windows通知时的时间

static int s_nPreHour;

static int s_nPreMinute;

static int s_nPreSecond;

// 窗口客户区的大小

static int s_cxClient;

static int s_cyClient;

// 是否位于最顶层

static BOOL s_bTopMost;

// time

SYSTEMTIME time;

// color

COLORREF crfColor;

// ID(Message)

int nID;

// Menu

HMENU hSysMenu;

 

//-------------------------------------------------------------------------------------

 

// function for internal use //--------------------------------------------------------

 

void DrawHandle(HDC hdc,int nLength,int nWidth,int nDegree,COLORREF clrColor);   // 绘制Clock指针

void SetIsotropic(HDC hdc, int cx, int cy);                                      // 设置坐标变换

void DrawClockFace(HDC hdc);                                                     // 绘制Clock

 

//-------------------------------------------------------------------------------------

 

 

// WinProc

 

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     PAINTSTRUCT ps;

     HDC hdc;

 

     switch (message)

     {

     case WM_CREATE:

         ::GetLocalTime(&time);

 

         s_nPreHour = time.wHour % 12;

         s_nPreMinute = time.wMinute;

         s_nPreSecond = time.wSecond;

 

         // 创建定时器

         ::SetTimer(hWnd,IDT_CLOCK,1000,NULL);

 

         // 设置菜单

         hSysMenu = ::GetSystemMenu(hWnd,FALSE);

         ::AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL);

         ::AppendMenu(hSysMenu,MF_STRING,IDM_TOPMOST,"总在最前");

         ::AppendMenu(hSysMenu,MF_STRING,IDM_HELP,"帮助");

 

         break;

     case WM_PAINT:

         hdc = BeginPaint(hWnd, &ps);

         {

         // 设置坐标系

         SetIsotropic(hdc,s_cxClient,s_cyClient);

         // 绘制钟表外观

         DrawClockFace(hdc);

         // 绘制钟表指针

         DrawHandle(hdc,200,8,s_nPreHour*30 + s_nPreMinute/2,RGB(0,0,0));

         DrawHandle(hdc,400,6,s_nPreMinute*6,RGB(0,0,0));

         DrawHandle(hdc, 400, 1, s_nPreSecond*6, RGB(0, 0, 0));

         }

         EndPaint(hWnd, &ps);

         break;

     case WM_TIMER:    // Timer

         // 判断窗口是否是最小化

         if (IsIconic(hWnd)) return 0;

 

         ::GetLocalTime(&time);

 

         // 建立坐标系

         hdc = ::GetDC(hWnd);

         SetIsotropic(hdc, s_cxClient, s_cyClient);

             

         crfColor = RGB(255,255,255);

             

         // 如果分钟改变的话就擦除时针和分针

         if(time.wMinute != s_nPreMinute)

         {

              // 擦除时针和分针

              DrawHandle(hdc, 200, 8, s_nPreHour*30 + s_nPreMinute/2, crfColor);

              DrawHandle(hdc, 400, 6, s_nPreMinute*6, crfColor);

              s_nPreHour = time.wHour;

              s_nPreMinute = time.wMinute;

         }

             

         // 如果秒改变的话就擦除秒针,然后重画所有指针

         if(time.wSecond != s_nPreSecond)

         {

              // 擦除秒针

              DrawHandle(hdc, 400, 1, s_nPreSecond*6, crfColor);

                  

              // 重画所有指针

              DrawHandle(hdc, 400, 1, time.wSecond*6, RGB(0, 0, 0));

              DrawHandle(hdc, 200, 8, time.wHour*30 + time.wMinute/2, RGB(0, 0, 0));

              DrawHandle(hdc, 400, 6, time.wMinute*6, RGB(0, 0, 0));

              s_nPreSecond = time.wSecond;

         }

         break;

     case WM_SIZE:

         s_cxClient = LOWORD(lParam);

         s_cyClient = HIWORD(lParam);

         break;

     case WM_NCHITTEST:      // 在无标题栏的窗口中,响应该消息可以在窗口的任意位置实现窗口的拖动功能

         UINT nHitTest;

         nHitTest = ::DefWindowProc(hWnd,WM_NCHITTEST,wParam,lParam);

 

         if (nHitTest == HTCLIENT && ::GetAsyncKeyState(MK_LBUTTON) < 0)

         {

              nHitTest = HTCAPTION;

         }

         return nHitTest;

     case WM_CONTEXTMENU:

         POINT pt;

         pt.x = LOWORD(lParam);

         pt.y = HIWORD(lParam);

 

         hSysMenu = ::GetSystemMenu(hWnd,FALSE);

         nID = ::TrackPopupMenu(hSysMenu,TPM_LEFTALIGN | TPM_RETURNCMD,pt.x,pt.y,0,hWnd,NULL);

         if (nID > 0)

         {

              ::SendMessage(hWnd,WM_SYSCOMMAND,nID,0);

         }

         break;

     case WM_SYSCOMMAND:

         nID = wParam;

         {

              if (nID == IDM_HELP)

              {

                   ::MessageBox(hWnd,"一个基于D游戏框架的时钟","时钟",0);

              }

              else if (nID == IDM_TOPMOST)

              {

                   hSysMenu = ::GetSystemMenu(hWnd,FALSE);

                   if (s_bTopMost)

                   {

                       ::CheckMenuItem(hSysMenu,IDM_TOPMOST,MF_UNCHECKED);

                       ::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);

                       s_bTopMost = FALSE;

                   }

                   else

                   {

                       ::CheckMenuItem(hSysMenu,IDM_TOPMOST,MF_CHECKED);

                       ::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);

                       s_bTopMost = TRUE;

                   }

              }

 

         }

         break;

     case WM_CLOSE:

         ::KillTimer(hWnd,IDT_CLOCK);

         ::DestroyWindow(hWnd);

         break;

     case WM_DESTROY:

         PostQuitMessage(0);

         break;

     default:

         break;

     }

     return DefWindowProc(hWnd, message, wParam, lParam);

}// end WindProc

 

 

// WINMAIN

 

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)

{

     WNDCLASSEX winclass;      // this holds the class we create

     HWND       hWnd;          // generic window handle

     MSG        msg;           // generic message

 

     // fill in the window class structure

     winclass.cbSize               = sizeof(WNDCLASSEX);

     winclass.style                = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;

     winclass.lpfnWndProc          = WindowProc;

     winclass.cbClsExtra           = 0;

     winclass.cbWndExtra           = 0;

     winclass.hInstance            = hInstance;

     winclass.hIcon                = ::LoadIcon(NULL,IDI_APPLICATION);

     winclass.hCursor              = ::LoadCursor(NULL,IDC_ARROW);

     winclass.hbrBackground        = (HBRUSH)::GetStockObject(WHITE_BRUSH);

     winclass.lpszMenuName         = NULL;

     winclass.lpszClassName        = WINDOW_CLASS_NAME;

     winclass.hIconSm              = ::LoadIcon(NULL,IDI_APPLICATION);

 

     // save the hInstance in global

     hInstance_app = hInstance;

 

     // register the window class

     if (!RegisterClassEx(&winclass))

         return (0);

 

     // create the window

     if (!(hWnd = ::CreateWindowEx(NULL,                                // extended style

                                   WINDOW_CLASS_NAME,                   // class

                                   "3D Game Console",                   // title

//                                 WS_OVERLAPPEDWINDOW | WS_VISIBLE,    // style

                                       WS_POPUP | WS_SYSMENU | WS_SIZEBOX | WS_VISIBLE,

                                       0,0,                                 // initial x, y

                                       800,600,                             // initial width, height

                                       NULL,                                // handle to parent

                                       NULL,                                // handle to menu

                                       hInstance,                           // instance of this application

                                       NULL)))                              // extra creation parms

         return (0);

 

     // save main window handle

     hMainWnd = hWnd;

 

     // enter main event loop

     while (TRUE)

     {

         // test if there is a message in queue,if so get it

         if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

         {

              // test if this is a quit

              if (msg.message == WM_QUIT)

                   break;

 

              // translate any accelerator keys

              TranslateMessage(&msg);

 

              // send the message to the window proc

              DispatchMessage(&msg);

 

         }// end if

 

     }// end while

 

     return (msg.wParam);

 

}// end WinMain

 

///

 

 

// function for internal use /

 

// Draw the clock handle //-------------------------------------------------------------------------------

 

void DrawHandle(HDC hdc,int nLength,int nWidth,int nDegree,COLORREF clrColor)

{

     // turn angle to radian

     double nRadians = (double)nDegree * (2 * 3.1415926 / 360);

     // compute the coordinate

     POINT pt[2];

     pt[0].x = (int)(nLength * sin(nRadians));

     pt[0].y = (int)(nLength * cos(nRadians));

     pt[1].x = -pt[0].x / 5;

     pt[1].y = -pt[0].y / 5;

     // create the pen

     HPEN hPen = ::CreatePen(PS_SOLID,nWidth,clrColor);

     HPEN hOldPen = (HPEN)::SelectObject(hdc,hPen);

     // paint the handle

     ::MoveToEx(hdc,pt[0].x,pt[0].y,NULL);

     ::LineTo(hdc,pt[1].x,pt[1].y);

     // delete the pen

     ::SelectObject(hdc,hOldPen);

     ::DeleteObject(hPen);

}

 

// Set the coordinate //--------------------------------------------------------------------------------

 

void SetIsotropic(HDC hdc, int cx, int cy)

{

     ::SetMapMode(hdc,MM_ISOTROPIC);             // 设置自定义映射模式

     ::SetWindowExtEx(hdc,1000,1000,NULL);       // 设置窗口的逻辑单位为/1000英寸

     ::SetViewportExtEx(hdc,cx,-cy,NULL);        // 设置视口的映射规则,x坐标不变,y坐标方向相反

     ::SetViewportOrgEx(hdc,cx/2,cy/2,NULL);     // 设置视口的坐标原点

}

 

 

// Draw the clock face //-------------------------------------------------------------------------------

 

void DrawClockFace(HDC hdc)

{

     const int SQUARESIZE = 20;      // 盘面时刻点圆的半径

     // 定义时刻点

     static POINT pt[] =

     {

         0, 450,       // 12

         225, 390, // 1

         390, 225, // 2

         450, 0,       // 3

         390, -225,    //... 下面的坐标是上面的点的对称点(以X轴、Y轴或原点对称)

         225, -390,

         0, -450,

         -225, -390,

         -390, -225,

         -450, 0,

         -390, 225,

         -225, 390

     };

     // 设置画刷

     ::SelectObject(hdc,::GetStockObject(BLACK_BRUSH));

     // 绘制时刻点圆

     for (int i = 0; i < 12; i++)

     {

         ::Ellipse(hdc,pt[i].x - SQUARESIZE, pt[i].y - SQUARESIZE, pt[i].x + SQUARESIZE, pt[i].y + SQUARESIZE);

     }

}

 

//------------------------------------------------------------------------------------------

    程序设计过程中,主要设计到Windows GDI的使用,计时器的使用,以及右键系统菜单的使用和如何在POPUP风格的窗口实现在窗口的任意区域都响应标题栏的事件等,详细见代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值