|
楼主 |
发表于 2015-3-11 16:06:33
|
显示全部楼层
#include<Windows.h>
#include<math.h>
#include"resource.h"
#define ID_TIME 1
#define ID_TOP 100
#define ID_HELP 101
LRESULT CALLBACK MainWndProc(HWND vHwnd, UINT vMsg, WPARAM wParam, LPARAM lParam);
void drawClockFace(HDC vHdc);// 绘制时钟的外观
void setCoordinate(HDC vHdc, int vX, int vY);//设置笛卡尔坐标系
void setFont(HDC vHdc, HFONT *vFont, int vFontBig);//设置字体大小
void drawHand(HDC vHdc, int vLength, int vWidth, int vDegrees, COLORREF vColor);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
char ClassName[] = "MainWinClass";
WNDCLASSEX wndClass;
// 用描述主窗口的参数填充 WNDCLASSEX 结构
wndClass.cbSize = sizeof(wndClass);// 结构的大小
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// 指定如果大小改变就重画
//CS_OWNDC让Windows 将每次对DC的设置都保存下来
wndClass.cbClsExtra = 0;// 没有额外的类内存
wndClass.cbWndExtra = 0;// 没有额外的窗口内存
wndClass.lpfnWndProc = MainWndProc;// 窗口函数指针
wndClass.hInstance = hInstance;// 实例句柄
wndClass.hIcon = ::LoadIcon(hInstance, (LPSTR)ID_CLOCKICON1);// 使用预定义图标
wndClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);//使用预定义的光标
wndClass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);// 使用白色背景画刷
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = ClassName;// 窗口类的名称
wndClass.hIconSm = NULL;//没有类的小图标
// 注册这个窗口类
::RegisterClassEx(&wndClass);
//创建主窗口
HWND hwnd = ::CreateWindowEx(
0, // dwExStyle,扩展样式
ClassName, // lpClassName,类名
"时钟", //lpWindowName,标题
WS_OVERLAPPEDWINDOW,//dwStyle,窗口风格
CW_USEDEFAULT, // X,初始 X 坐标
CW_USEDEFAULT, //Y,初始 Y 坐标
500, // nWidth,宽度
500, //nHeight,高度
NULL, // hWndParent,父窗口句柄
NULL, //hMenu,菜单句柄
hInstance, //hlnstance,程序实例句柄
NULL // lpParam,用户数据
);
if (hwnd == NULL)
{
::MessageBox(NULL, "创建窗口出错! ", "error", MB_OK);
return -1;
}
// 显示窗口,刷新窗口客户区
::ShowWindow(hwnd, SW_SHOWNORMAL);
::UpdateWindow(hwnd);
// 从消息队列中取出消息,交给窗口函数处理,直到 GetMessage 返回 FALSE,结束消息循环
MSG msg;
while(::GetMessage(&msg, NULL, 0, 0))
{
// 转化键盘消息
::TranslateMessage(&msg);
// 将消息发送到相应的窗口函数
::DispatchMessage(&msg);
}
// 当 GetMessage 返回 FALSE 时程序结束
return msg.wParam;
}
//******************************************************************
//FUNCTION:
LRESULT CALLBACK MainWndProc(HWND vHwnd, UINT vMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
HFONT hFont;//字体句柄
// 上一次 Windows通知时的时间
static int PreHour;
static int PreMinute;
static int PreSecond;
// 窗口客户区的大小
static int xClient;
static int yClient;
// 是否位于最顶层
static BOOL FlagTop;
switch (vMsg)
{
case WM_CREATE:
//在窗口刚被创建,即接受到 WM_CREATE消息的时候,要初始化全局变量的值,并安装定时器。
{
HMENU hmenu;
hmenu = ::LoadMenu((HINSTANCE)::GetWindowLongPtr(vHwnd, GWL_HINSTANCE), MAKEINTRESOURCE(ID_CLOCK));
SetMenu(vHwnd, hmenu);
//设置字体
hdc = ::BeginPaint(vHwnd, &ps);
setFont(hdc, &hFont, 30);
// 向系统菜单中添加自定义的项
HMENU sysMenu;
sysMenu = ::GetSystemMenu(vHwnd, false);
::AppendMenu(sysMenu, MF_SEPARATOR, 0, NULL);
::AppendMenu(sysMenu, MF_STRING, ID_TOP, "总在最前");
::AppendMenu(sysMenu, MF_STRING, ID_HELP, "帮助");
// 设置时间
SYSTEMTIME time;
::GetLocalTime(&time);
PreHour = time.wHour;
PreMinute = time.wMinute;
PreSecond = time.wSecond;
// 创建定时器
::SetTimer(vHwnd, ID_TIME, 1000, NULL);
break;
}
case WM_SIZE:
{
xClient = LOWORD(lParam);
yClient = HIWORD(lParam);
break;
}
case WM_PAINT:
{
// 使无效的客户区变的有效,并取得设备环境句柄
hdc = ::BeginPaint(vHwnd, &ps);
//::GetClientRect(vHwnd, &Rect);
setCoordinate(hdc, xClient, yClient);// 设置坐标系
drawClockFace(hdc);// 绘制时钟外观
// 绘制指针
// 经过 1 个小时时针走30 度(360/12 ),经过 1 分钟时针走0.5度(30/60)
drawHand(hdc, 200, 8, (PreHour*30 + PreMinute/2), RGB(0,0,0));
// 经过 1 分钟分针走6 度(360/60 )
drawHand(hdc, 400, 6, PreMinute*6, RGB(10,0,0));
// 经过 1 秒钟秒针走6 度(360/60 )
drawHand(hdc, 400, 4, PreSecond*6, RGB(10,10,0));
::EndPaint(vHwnd, &ps);
break;
}
case WM_COMMAND://菜单响应
{
switch (LOWORD(wParam))
{
case ID_INFO:
{
::SendMessage(vHwnd, WM_CLOSE, 0, 0);
break;
}
case ID_HELLO:
{
int MsgBox = ::MessageBox(vHwnd, "hello world", "问好", MB_YESNO | MB_DEFBUTTON2);
break;
}
default:
break;
}
break;
}
case WM_TIMER:
{
if (::IsIconic(vHwnd))// IsIconic 函数用来判断窗口是否处于最小化状态
break;
// 取得系统时间
SYSTEMTIME time;
::GetLocalTime(&time);
// 建立坐标系
hdc = ::GetDC(vHwnd);
// 以COLOR_3DFACE为背景色就可以擦除指针了(因为窗口的背景色也是COLOR_3DFACE)
COLORREF sysColor = ::GetSysColor(COLOR_3DFACE);
// 如果分钟改变的话就擦除时针和分针
if (PreMinute != time.wMinute)
{
drawHand(hdc, 200, 8, (PreHour*30 + PreMinute/2), sysColor);
drawHand(hdc, 400, 6, PreMinute*6, sysColor);
PreHour = time.wHour;
PreMinute = time.wMinute;
}
// 如果秒改变的话就擦除秒针,然后重画所有指针
if (PreSecond != time.wSecond)
{
//擦除秒针
drawHand(hdc, 400, 4, PreSecond*6, sysColor);
//重画所有指针
// 经过 1 个小时时针走30 度(360/12 ),经过 1 分钟时针走0.5度(30/60)
drawHand(hdc, 200, 8, (time.wHour*30 + time.wMinute/2), RGB(0,0,0));
// 经过 1 分钟分针走6 度(360/60 )
drawHand(hdc, 400, 6, time.wMinute*6, RGB(10,0,0));
// 经过 1 秒钟秒针走6 度(360/60 )
drawHand(hdc, 400, 4, time.wSecond*6, RGB(10,10,0));
PreSecond = time.wSecond;
}
break;
}
case WM_NCHITTEST:
{
UINT HitTest;
HitTest = ::DefWindowProc(vHwnd, WM_NCHITTEST, wParam, lParam);
//// 如果鼠标左键按下,GetAsyncKeyState函数的返回值小于0
if (HitTest == HTCLIENT && ::GetAsyncKeyState(MK_LBUTTON) < 0)
{
HitTest = HTCAPTION;
}
return HitTest;
}
case WM_CONTEXTMENU:
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
// 取得系统菜单的句柄
HMENU SysMenu = ::GetSystemMenu(vHwnd, FALSE);//允许应用程序为复制或修改而访问窗口菜单
//通过api函数getsystemmenu来得到它的句柄,然后通过菜单相关的api函数就能改变它了。
// 弹出系统菜单
int MenuID;
MenuID = ::TrackPopupMenu(
SysMenu, // 菜单句柄
TPM_LEFTBUTTON, // 此参数指定了一些和弹出的菜单的位置相关的选项
pt.x, //(x, y)是弹出的菜单的基于屏幕的坐标
pt.y,
0, //保留值,必须为零
vHwnd, // 此菜单属于哪一个窗口所有(也就是WM_COMMAND消息发到这个窗口)
NULL);
if (MenuID > 0)
{
::SendMessage(vHwnd, WM_SYSCOMMAND, MenuID, 0);
}
return 0;
}
case WM_SYSCOMMAND:
{
int ID = wParam;
if (ID == ID_HELP)
{
::MessageBox(vHwnd, "时钟显示", "时钟", 0);
}
else if (ID == ID_TOP)
{
HMENU sysMenu = ::GetSystemMenu(vHwnd, false);
if (FlagTop)
{
// 设置 ID号为 IDM_TOPMOST 的菜单项为未选中状态
::CheckMenuItem(sysMenu, ID_TOP, MF_UNCHECKED);
// 将窗口提到所有窗口的最顶层
::SetWindowPos(vHwnd,HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
FlagTop = false;
}
else
{
::CheckMenuItem(sysMenu, ID_TOP, MF_CHECKED);
::SetWindowPos(vHwnd,HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
FlagTop = true;
}
}
return ::DefWindowProc(vHwnd, WM_SYSCOMMAND, ID, 0);
}
case WM_CLOSE:
{
::KillTimer(vHwnd, ID_TIME);
int MsgBox = ::MessageBox(vHwnd, "确定要关闭窗口吗?", "询问", MB_YESNO | MB_DEFBUTTON2);
if(MsgBox == IDYES)
DestroyWindow(vHwnd);
break;
}
case WM_DESTROY:
{
// 向消息队列投递一个 WM_QUIT 消息,促使 GetMessage 函数返回 0,结束消息循环
::PostQuitMessage(0);
break;
}
default:
return ::DefWindowProc(vHwnd, vMsg, wParam, lParam);
}
return 0;
}
//******************************************************************
//FUNCTION:
void drawClockFace(HDC vHdc)
{
const int SQUAREsize = 20;
char ClockNum[10];
static POINT ClockPt[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,
0, 450 // 12 点
};
// 选择一个黑色的画刷
::SelectObject(vHdc, ::GetStockObject(BLACK_BRUSH));
// 画12 个圆
for (int i =0; i<12; i++)
{
::Ellipse(vHdc, ClockPt[i].x - SQUAREsize, ClockPt[i].y + SQUAREsize,
ClockPt[i].x + SQUAREsize, ClockPt[i].y - SQUAREsize);
wsprintf(ClockNum, "%d", i+1);
::TextOut(vHdc, ClockPt[i].x - 10, ClockPt[i].y - 20, ClockNum, strlen(ClockNum));
}
}
//******************************************************************
//FUNCTION:
void setCoordinate(HDC vHdc, int vX, int vY)
{
::SetMapMode(vHdc, MM_ISOTROPIC);
::SetWindowExtEx(vHdc, 1000, 1000, NULL);
::SetViewportExtEx(vHdc, vX, -vY, NULL);
::SetViewportOrgEx(vHdc, vX/2, vY/2, NULL);
}
//******************************************************************
//FUNCTION:
void setFont(HDC vHdc, HFONT *vFont, int vFontBig)
{
*vFont = ::CreateFont(
35, 0,//高度20, 宽取0表示由系统选择最佳值
0, 0,//文本倾斜,与字体倾斜都为0
FW_HEAVY,//粗体
0, 0, 0,//非斜体,无下划线,无中划线
GB2312_CHARSET, //字符集
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, //一系列的默认值
DEFAULT_PITCH | FF_DONTCARE,
"自定义字体" //字体名称
);//自定义字体
SelectObject(vHdc, *vFont);
DeleteObject(*vFont);
}
//******************************************************************
//FUNCTION:
void drawHand(HDC vHdc, int vLength, int vWidth, int vDegrees, COLORREF vColor)
{
double Radian = (double)vDegrees * ( (2*3.1415926)/360 );
// 计算坐标
POINT pt[2];
pt[0].x = (int)(vLength * sin(Radian));
pt[0].y = (int)(vLength * cos(Radian));
pt[1].x = -pt[0].x/5;
pt[1].y = -pt[0].y/5;
// 创建画笔,并选如DC结构中
HPEN hPen = ::CreatePen(PS_SOLID, vWidth, vColor);
HPEN hOldPen = (HPEN)::SelectObject(vHdc, hPen);
// 画线
::MoveToEx(vHdc, pt[0].x, pt[0].y, NULL);
::LineTo(vHdc, pt[1].x, pt[1].y);
::SelectObject(vHdc, hOldPen);
::DeleteObject(hPen);
}
|
|