#include "stdafx.h"
#include "小时钟.h"
#include <math.h>
#include <time.h>
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MY, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MY));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MY);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
#define IDT_CLOCK 1
const int IDM_HELP = 100;
const int IDM_TOPMOST = 101;
// 实现函数
void SetIsotropic(HDC hdc, int cxClient, int cyClient);
void DrawClockFace(HDC hdc);
void DrawHand(HDC hdc, int nLength, int nWidth, int nDegrees, COLORREF clrColor);
// 上一次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;
LRESULT __stdcall WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
switch (nMsg)
{
case WM_CREATE:
{
// 向系统菜单中添加自定义的项
HMENU hSysMenu;
hSysMenu = ::GetSystemMenu(hWnd, FALSE);
::AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL); //分界线
::AppendMenu(hSysMenu, MF_STRING, IDM_TOPMOST, "总在最前");
::AppendMenu(hSysMenu, MF_STRING, IDM_HELP, "帮助");
// 设置时间
SYSTEMTIME time;
::GetLocalTime(&time);
s_nPreHour = time.wHour % 12;
s_nPreMinute = time.wMinute;
s_nPreSecond = time.wSecond;
// 创建定时器
::SetTimer(hWnd, IDT_CLOCK, 1000, NULL);
return 0;
}
case WM_SIZE:
{
s_cxClient = LOWORD(lParam);
s_cyClient = HIWORD(lParam);
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = ::BeginPaint(hWnd, &ps);
// 设置坐标系
TextOut(hdc, 10, 10, "许振辉是天才", strlen("许振辉是天才"));
SetIsotropic(hdc, s_cxClient, s_cyClient);
// 绘制时钟外观
DrawClockFace(hdc);
// 绘制指针
// 经过1个小时时针走30度(360/12),经过1分钟时针走0.5度(30/60)
DrawHand(hdc, 200, 8, s_nPreHour * 30 + s_nPreMinute / 2, RGB(0, 0, 0));
// 经过1分钟分针走6度(360/60)
DrawHand(hdc, 400, 6, s_nPreMinute * 6, RGB(0, 0, 0));
// 经过1秒钟秒针走6度(360/60)
DrawHand(hdc, 400, 1, s_nPreSecond * 6, RGB(0, 0, 0));
::EndPaint(hWnd, &ps);
return 0;
}
case WM_TIMER:
{
// 如果窗口处于最小化状态就什么也不做
if (::IsIconic(hWnd)) // IsIconic函数用来判断窗口是否处于最小化状态
return 0;
// 取得系统时间
SYSTEMTIME time;
::GetLocalTime(&time);
// 建立坐标系
HDC hdc = ::GetDC(hWnd);
SetIsotropic(hdc, s_cxClient, s_cyClient);
// 以COLOR_3DFACE为背景色就可以擦除指针了(因为窗口的背景色也是COLOR_3DFACE)
COLORREF crfColor = ::GetSysColor(COLOR_3DFACE);
// 如果分钟改变的话就擦除时针和分针
if (time.wMinute != s_nPreMinute)
{
// 擦除时针和分针
DrawHand(hdc, 200, 8, s_nPreHour * 30 + s_nPreMinute / 2, crfColor);
DrawHand(hdc, 400, 6, s_nPreMinute * 6, crfColor);
s_nPreHour = time.wHour;
s_nPreMinute = time.wMinute;
}
// 如果秒改变的话就擦除秒针,然后重画所有指针
if (time.wSecond != s_nPreSecond)
{
// 擦除秒针
DrawHand(hdc, 400, 1, s_nPreSecond * 6, crfColor);
// 重画所有指针
DrawHand(hdc, 400, 1, time.wSecond * 6, RGB(0, 0, 0));
DrawHand(hdc, 200, 8, time.wHour * 30 + time.wMinute / 2, RGB(0, 0, 0));
DrawHand(hdc, 400, 6, time.wMinute * 6, RGB(0, 0, 0));
s_nPreSecond = time.wSecond;
}
return 0;
}
case WM_CONTEXTMENU:
POINT pt; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam);
{
// 取得系统菜单的句柄
HMENU hSysMenu = ::GetSystemMenu(hWnd, FALSE);
// 弹出系统菜单
int nID = ::TrackPopupMenu(hSysMenu, TPM_LEFTALIGN | TPM_RETURNCMD,
pt.x, pt.y, 0, hWnd, NULL);
if (nID > 0)
::SendMessage(hWnd, WM_SYSCOMMAND, nID, 0);
return 0;
}
case WM_CLOSE:
{
::KillTimer(hWnd, IDT_CLOCK);
::DestroyWindow(hWnd);
return 0;
}
case WM_DESTROY:
{
::PostQuitMessage(0);
return 0;
}
case WM_NCHITTEST:
{
UINT nHitTest;
nHitTest = ::DefWindowProc(hWnd, WM_NCHITTEST, wParam, lParam);
if (nHitTest == HTCLIENT &&
::GetAsyncKeyState(MK_LBUTTON) < 0) // 如果鼠标左键按下,GetAsyncKeyState函数的返回值小于0
nHitTest = HTCAPTION;
return nHitTest;
}
case WM_SYSCOMMAND:
int nID = wParam;
{
if (nID == IDM_HELP)
{
::MessageBox(hWnd, "一个时钟的例子", "时钟", 0);
}
else if (nID == IDM_TOPMOST)
{
HMENU 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_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
s_bTopMost = TRUE;
}
}
return ::DefWindowProc(hWnd, WM_SYSCOMMAND, nID, 0);
}
}
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}
void SetIsotropic(HDC hdc, int cx, int cy)
{
::SetMapMode(hdc, MM_ISOTROPIC);
::SetWindowExtEx(hdc, 1000, 1000, NULL);
::SetViewportExtEx(hdc, cx, -cy, NULL);
::SetViewportOrgEx(hdc, cx / 2, cy / 2, NULL);
}
// 绘制时钟的外观
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));
// 画12个圆
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);
}
}
// 指针的长度、宽度、相对于0点偏移的角度、颜色分别由参数nLength、nWidth、nDegrees、clrColor指定
void DrawHand(HDC hdc, int nLength, int nWidth, int nDegrees, COLORREF clrColor)
{
// 将角度nDegrees转化成弧度 . 2*3.1415926/360 == 0.0174533
double nRadians = (double)nDegrees*0.0174533;
// 计算坐标
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;
// 创建画笔,并选如DC结构中
HPEN hPen = ::CreatePen(PS_SOLID, nWidth, clrColor);
HPEN hOldPen = (HPEN)::SelectObject(hdc, hPen);
// 画线
::MoveToEx(hdc, pt[0].x, pt[0].y, NULL);
::LineTo(hdc, pt[1].x, pt[1].y);
::SelectObject(hdc, hOldPen);
::DeleteObject(hPen);
}