win32GDI項目數(shù)字時鐘
前言:基于win32GDI繪圖制作抖音熱門數(shù)字時鐘
定時器
開啟定時器
//定義定時器ID
#define IDT_TIME 1001
//設(shè)置定時器
SetTimer(hWnd
, IDT_TIME //定時器ID
, 1000 //定時間隔 單位毫秒ms
, NULL); //參數(shù)為NULL時以政,定時向程序投遞WM_TIMER消息
匹配定時器消息
case WM_TIMER:
switch (wParam)
{
case IDT_TIME:
{
HDC hdc = GetDC(hWnd);
static int y = 0;
TextOut(hdc, 0, y += 20, L"定時器開啟第",6);
ReleaseDC(hWnd, hdc);
}
break;
default:
break;
}
break;
關(guān)閉定時器
KillTimer(hWnd, IDT_TIME);
系統(tǒng)時間
系統(tǒng)時間結(jié)構(gòu)體 SYSTEMTIME
獲取系統(tǒng)時間
wchar_t szTime[100];
SYSTEMTIME currentTime;
GetLocalTime(¤tTime);
wsprintf(szTime, L"%.2d %.2d %.2d %.2d:%.2d:%.2d\n", currentTime.wYear,
currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);
TextOut(hdc, 0, 0, szTime, wcslen(szTime) - 1);
定時器+時鐘 = 簡陋的數(shù)字時鐘
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
wchar_t szTime[100];
SYSTEMTIME currentTime;
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, IDT_TIME, 1000, NULL);
break;
case WM_RBUTTONDOWN:
KillTimer(hWnd, IDT_TIME);
break;
case WM_TIMER:
switch (wParam)
{
case IDT_TIME:
{
HDC hdc = GetDC(hWnd);
GetLocalTime(¤tTime);
wsprintf(szTime, L"%.2d %.2d %.2d %.2d:%.2d:%.2d\n", currentTime.wYear,
currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);
TextOut(hdc, 0, 0, szTime, wcslen(szTime) - 1);
ReleaseDC(hWnd, hdc);
}
break;
default:
break;
}
break;
case WM_COMMAND:
break;
case WM_PAINT:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
效果顯示
去標題欄
創(chuàng)建窗口的時候自定義窗口風格
// 創(chuàng)建主窗口
HWND hwnd = CreateWindowEx(
0, // dwExStyle,擴展樣式
szClassName, // lpClassName级零,類名
L"時鐘", // lpWindowName横浑,標題
WS_POPUP|WS_SYSMENU|WS_SIZEBOX, // dwStyle,窗口風格 WS_POPUP|WS_SYSMENU去標題欄所需宏
100, // X,初始 X 坐標
100, // Y邦危,初始 Y 坐標
300, // nWidth,寬度
300, // nHeight舍扰,高度
NULL, // hWndParent倦蚪,父窗口句柄
NULL, // hMenu,菜單句柄
hInstance, // hlnstance边苹,程序?qū)嵗浔?
NULL); // lpParam审丘,用戶數(shù)據(jù)
移動窗口
截取DefWindowProc消息
case WM_NCHITTEST:
{
UINT nHitTest;
//截取DefWindowProc消息
nHitTest = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
//如果鼠標左鍵按下 GetAsyncKeyState函數(shù)的返回值小于0
if (nHitTest == HTCLIENT && GetAsyncKeyState(MK_LBUTTON) < 0)
{
//改變DefWindowProc消息
nHitTest = HTCAPTION;
}
return nHitTest;
}
break;
給系統(tǒng)菜單追加菜單項
定義菜單ID
#define IDM_HELP 1001
#define IDM_TOPMOST 1002
追加菜單
case WM_CREATE:
{
HMENU hSysMenu = GetSystemMenu(hwnd, FALSE); //獲取系統(tǒng)菜單
AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL); //添加分割線
AppendMenu(hSysMenu, MF_STRING, IDM_TOPMOST, L"總是在前");
AppendMenu(hSysMenu, MF_STRING, IDM_HELP, L"幫助");
}
右鍵菜單
這個不能算是右鍵菜單,因為截取了DefWindowProc消息勾给,多以對客戶區(qū)的右鍵相當于對標題欄的右鍵彈出的是系統(tǒng)菜單
case WM_CONTEXTMENU:
{
POINT pt;
//lParam包含了鼠標的位置消息 低位x,高位y
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
//獲取系統(tǒng)菜單
HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
//彈出系統(tǒng)菜單
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;
}
break;
對菜單操作進行響應
全局添加是否頂置標識符
static int s_bTopMost = 0;
響應菜單
注冊窗口的時候窗口風格必須帶上WS_SYSMENU
case WM_SYSCOMMAND:
{
int nId = wParam;
switch (nId)
{
case IDM_HELP:
MessageBox(hwnd, L"一個小時鐘程序", L"幫助", 0);
break;
case 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);
}
break;
完整代碼顯示
#include <windows.h>
#define IDM_HELP 1001
#define IDM_TOPMOST 1002
// 窗口函數(shù)的函數(shù)原形
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WCHAR szClassName[] = L"MainWClass";//窗口類的名稱
WNDCLASSEX wndclass;
// 用描述主窗口的參數(shù)填充WNDCLASSEX結(jié)構(gòu)
wndclass.cbSize = sizeof(wndclass); // 結(jié)構(gòu)的大小
wndclass.style = CS_HREDRAW | CS_VREDRAW; // 指定如果大小改變就重畫
wndclass.lpfnWndProc = MainWndProc; // 窗口函數(shù)指針
wndclass.cbClsExtra = 0; // 沒有額外的類內(nèi)存
wndclass.cbWndExtra = 0; // 沒有額外的窗口內(nèi)存
wndclass.hInstance = hInstance; // 實例句柄
wndclass.hIcon = LoadIcon(NULL,
IDI_APPLICATION); // 使用預定義圖標
wndclass.hCursor = LoadCursor(NULL,
IDC_ARROW); // 使用預定義的光標
wndclass.hbrBackground = (HBRUSH)
::GetStockObject(WHITE_BRUSH); // 使用白色背景畫刷
wndclass.lpszMenuName = NULL; // 不指定菜單
wndclass.lpszClassName = szClassName; // 窗口類的名稱
wndclass.hIconSm = NULL; // 沒有類的小圖標
// 注冊這個窗口類
RegisterClassEx(&wndclass);
// 創(chuàng)建主窗口
HWND hwnd = CreateWindowEx(
0, // dwExStyle锅知,擴展樣式
szClassName, // lpClassName播急,類名
L"時鐘", // lpWindowName,標題
WS_POPUP|WS_SYSMENU|WS_SIZEBOX, // dwStyle售睹,窗口風格
100, // X桩警,初始 X 坐標
100, // Y,初始 Y 坐標
300, // nWidth昌妹,寬度
300, // nHeight捶枢,高度
NULL, // hWndParent握截,父窗口句柄
NULL, // hMenu,菜單句柄
hInstance, // hlnstance烂叔,程序?qū)嵗浔?
NULL); // lpParam谨胞,用戶數(shù)據(jù)
if (hwnd == NULL)
{
MessageBox(NULL, L"創(chuàng)建窗口出錯!", L"error", MB_OK);
return -1;
}
// 顯示窗口蒜鸡,刷新窗口客戶區(qū)
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 從消息堆中取出消息
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0))
{
// 轉(zhuǎn)化鍵盤消息
TranslateMessage(&msg);
// 將消息發(fā)送到相應的窗口函數(shù)
DispatchMessage(&msg);
}
// 當GetMessage返回0時程序結(jié)束
return msg.wParam;
}
static int s_bTopMost = 0;
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR szText[] = L"第一個win32程序胯努!";
switch (message)
{
case WM_CREATE:
{
HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL); //添加分割線
AppendMenu(hSysMenu, MF_STRING, IDM_TOPMOST, L"總是在前");
AppendMenu(hSysMenu, MF_STRING, IDM_HELP, L"幫助");
}
break;
case WM_NCHITTEST:
{
UINT nHitTest;
//截取DefWindowProc消息
nHitTest = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
//如果鼠標左鍵按下 GetAsyncKeyState函數(shù)的返回值小于0
if (nHitTest == HTCLIENT && GetAsyncKeyState(MK_LBUTTON) < 0)
{
//改變DefWindowProc消息
nHitTest = HTCAPTION;
}
return nHitTest;
}
break;
case WM_CONTEXTMENU:
{
POINT pt;
//lParam包含了鼠標的位置消息 低位x,高位y
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
//獲取系統(tǒng)菜單
HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
//彈出系統(tǒng)菜單
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;
}
break;
case WM_SYSCOMMAND:
{
int nId = wParam;
switch (nId)
{
case IDM_HELP:
MessageBox(hwnd, L"一個小時鐘程序", L"幫助", 0);
break;
case 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);
}
break;
default:
break;
}
}
break;
case WM_PAINT: // 窗口客戶區(qū)需要重畫
{
HDC hdc;
PAINTSTRUCT ps;
// 使無效的客戶區(qū)變的有效逢防,并取得設(shè)備環(huán)境句柄
hdc = BeginPaint(hwnd, &ps);
// 顯示文字
//TextOut(hdc, 10, 10, szText, wcslen(szText));
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY: // 正在銷毀窗口
// 向消息隊列投遞一個WM_QUIT消息叶沛,促使GetMessage函數(shù)返回0,結(jié)束消息循環(huán)
PostQuitMessage(0);
return 0;
}
// 將我們不處理的消息交給系統(tǒng)做默認處理
return DefWindowProc(hwnd, message, wParam, lParam);
}
設(shè)置坐標
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
//獲取客戶區(qū)大小
RECT rt;
GetClientRect(hWnd, &rt);
int cx = rt.right;
int cy = rt.bottom;
SetViewportExtEx(hdc, cx, cy, NULL); //設(shè)置x,y坐標軸
SetViewportOrgEx(hdc, 0, 0, NULL); //設(shè)置原點
EndPaint(hWnd, &ps);
}
了解這些win32基礎(chǔ)知識之后我們來繪制一個數(shù)字時鐘