/*--------------------------------------
CLOCK.C -- Analog Clock Program
(c) Charles Petzold, 1998
--------------------------------------*/
#include <windows.h>
#include <math.h>
#define ID_TIMER 1
#define TWOPI (2 * 3.14159)
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Clock") ;
HWND hwnd;
MSG msg;
WNDCLASS wndclass ;
//定义窗口类型为当窗口在水平或垂直方向上变化时将重绘窗口
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
//指定窗口的过程函数,窗口的过程函数是回调函数
wndclass.lpfnWndProc = WndProc ;
//类附加内存空间
wndclass.cbClsExtra = 0 ;
//窗口附加内存空间
wndclass.cbWndExtra = 0 ;
//指定包含窗口过程的车工女婿的实例句柄
wndclass.hInstance = hInstance ;
//指定窗口类的图标句柄
wndclass.hIcon = NULL ;
//指定窗口类的光标句柄
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
//指定窗口类的背景画刷句柄
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
//指定菜单资源的名字
wndclass.lpszMenuName = NULL ;
//指定窗口类的名字
wndclass.lpszClassName = szAppName ;
//完成窗口类(WNDCLASS)后,需要调用RegisterClass函数才能对其进行注册,注册成功后,才可以创建该类型的窗口,注册函数原型:
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (
//指定窗口类的名称
szAppName,
//指定窗口的名字
TEXT ("Analog Clock"),
//创建窗口的样式
WS_OVERLAPPEDWINDOW,
//窗口的左上角(x,y)坐标
100, 100,
//窗口的宽度,高度
1000, 1000,
//指定被创建的窗口的父窗口句柄
NULL,
//指定窗口菜单的句柄
NULL,
//指定窗口所属的应用程序的实例的句柄
hInstance,
//WM_CREATE消息的附加参数
NULL
) ;
//显示窗口
ShowWindow (hwnd, iCmdShow) ;
//更新窗口
UpdateWindow (hwnd) ;
//消息循环
while (GetMessage (&msg, NULL, 0, 0))
{
//将虚拟一键消息转换为字符消息
TranslateMessage (&msg) ;
//分派一个消息到窗口句柄过程,有窗口过程函数对消息进行处理。
//DispatchMessage实际是将消息回传给操作系统,有操作系统调用窗口过程函数对消息进行处理
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
void SetIsotropic (HDC hdc, int cxClient, int cyClient)
{
/*
The mapping mode defines the unit of measure used to convert logical units to device units
MM_ISOTROPIC--one unit along the x-axis is equal to one unit along the y-axis
*/
SetMapMode (hdc, MM_ISOTROPIC) ;
/*
SetWindowExtEx
The SetWindowExtEx function sets the horizontal and
vertical extents of the window for a device context by using the specified values.
BOOL SetWindowExtEx(
HDC hdc, // handle to device context
int nXExtent, // new horizontal window extent
int nYExtent, // new vertical window extent
LPSIZE lpSize // original window extent
);
*/
SetWindowExtEx (hdc, 1000, 1000, NULL) ;
/*
The SetViewportExtEx function sets the horizontal and vertical extents of the viewport
for a device context by using the specified values.
*/
SetViewportExtEx (hdc, cxClient/ 2 ,-cyClient/ 2 , NULL) ;
/*
The SetViewportOrgEx function specifies which device point maps to the window origin (0,0).
BOOL SetViewportOrgEx(
HDC hdc, // handle to device context
int X, // new x-coordinate of viewport origin
int Y, // new y-coordinate of viewport origin
LPPOINT lpPoint // original viewport origin
); */
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;
}
/*
iNum个pt点阵饶逻辑原点旋转iAngle的角度
*/
void RotatePoint (POINT pt[], int iNum, int iAngle)
{
int i ;
POINT ptTemp ;
for (i = 0 ; i < iNum ; i++)
{
ptTemp.x = (int) (pt[i].x * cos (TWOPI * iAngle / 360) +
pt[i].y * sin (TWOPI * iAngle / 360)) ;
ptTemp.y = (int) (pt[i].y * cos (TWOPI * iAngle / 360) -
pt[i].x * sin (TWOPI * iAngle / 360)) ;
pt[i] = ptTemp ;
}
}
void DrawClock (HDC hdc)
{
int iAngle ;
POINT pt[3] ;
for (iAngle = 0 ; iAngle < 360 ; iAngle += 6)
{
pt[0].x = 0 ;
pt[0].y = 900 ;
RotatePoint (pt, 1, iAngle) ;
pt[2].x = pt[2].y = iAngle % 5 ? 33 : 100 ;
pt[0].x -= pt[2].x / 2 ;
pt[0].y -= pt[2].y / 2 ;
pt[1].x = pt[0].x + pt[2].x ;
pt[1].y = pt[0].y + pt[2].y ;
SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ;
Ellipse (hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y) ;
}
}
void DrawHands (HDC hdc, SYSTEMTIME * pst, BOOL fChange)
{
static POINT pt[3][5] = { 0, -150, 100, 0, 0, 600, -100, 0, 0, -150,
0, -200, 50, 0, 0, 800, -50, 0, 0, -200,
0, 0, 0, 0, 0, 0, 0, 0, 0, 800 } ;
int i, iAngle[3] ;
POINT ptTemp[3][5] ;
iAngle[0] = (pst->wHour * 30) % 360 + pst->wMinute / 2 ;
iAngle[1] = pst->wMinute * 6 ;
iAngle[2] = pst->wSecond * 6 ;
memcpy (ptTemp, pt, sizeof (pt)) ;
for (i = fChange ? 0 : 2 ; i < 3 ; i++)
{
RotatePoint (ptTemp[i], 5, iAngle[i]) ;
Polyline (hdc, ptTemp[i], 5) ;
}
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxClient, cyClient ;
static SYSTEMTIME stPrevious ;
BOOL fChange ;
HDC hdc ;
PAINTSTRUCT ps ;
SYSTEMTIME st ;
switch (message)
{
case WM_CREATE :
/*
If lpTimerFunc is NULL, the system posts a WM_TIMER message to the application queue.
The hwnd member of the message's MSG structure contains the value of the hWnd parameter.
*/
SetTimer (hwnd, ID_TIMER, 1000, NULL) ;
/*
This function retrieves the current local date and time.
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;
*/
GetLocalTime (&st) ;
stPrevious = st ;
return 0 ;
case WM_SIZE :
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_TIMER :
GetLocalTime (&st) ;
fChange = st.wHour != stPrevious.wHour ||
st.wMinute != stPrevious.wMinute ;
hdc = GetDC (hwnd) ;
SetIsotropic (hdc, cxClient, cyClient) ;
SelectObject (hdc, GetStockObject (WHITE_PEN)) ;
DrawHands (hdc, &stPrevious, fChange) ;
SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
DrawHands (hdc, &st, TRUE) ;
ReleaseDC (hwnd, hdc) ;
stPrevious = st ;
return 0 ;
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
SetIsotropic (hdc, cxClient, cyClient) ;
DrawClock (hdc) ;
DrawHands (hdc, &stPrevious, TRUE) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY :
KillTimer (hwnd, ID_TIMER) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}