Window核心编程笔记(5)
文章目录
1.键盘消息2.鼠标消息3.定时器消息4.菜单资源5.上下文菜单
1.键盘消息
键盘消息分类:
· WM_KEYDOWN - 摁键被摁下时产生
· WM_KEYUP - 摁键被放开时产生
· WM_SYSKEYDOWN - 系统键按下时产生,例如ALT、F10
· WM_SYSKEYUP - 系统键放开时产生
附带信息: WPARAM - 摁键的Virtual Key LPARAM - 按键的参数,例如按下次数 测试一下效果:
void on_keydown(HWND hwnd,WPARAM wParam)
{
wchar_t text[256] = {0};
wsprintf(text, L"键值为%d", wParam);
WriteConsole(g_out, text, wcslen(text), NULL, NULL);
}
void on_keyup(HWND hwnd)
{
MessageBox(hwnd, L"按键被释放", L"infor", MB_OK);
}
摁下按键时在DOS窗口打印键值,松开摁键后跳出提示窗口
2.字符消息 · TranslateMessage在转换WM_KEYDOWN消息时,对于可见字符可以产生WM_CHAR,不可见字符无此消息
· 附带信息: WPARAM - 输入的字符的ASCII字符编码 LPARAM - 按键的相关参数
2.鼠标消息
1.鼠标消息分类 · 基本鼠标消息 WM_LBUTTONDOWN - 鼠标左键摁下 WM_LBUTTONUP - 鼠标做键抬起 WM_LBUTTONDOWN - 鼠标右键摁下 WM_LBUTTONUP - 鼠标右键抬起 WM_MOUSEMOVE - 鼠标移动消息
· 双击消息 WM_LBUTTONBLCLK - 鼠标左键双击 WM_RBUTTONBLCLK - 鼠标右键双击
· 滚轮消息 WM_MOUSEWHEEL - 鼠标滚轮消息
鼠标基本消息: wPARAM : 其他按键状态,例如Ctrl/Shift等 lPARAM : 鼠标的位置,窗口客户区坐标系 LOWORD X坐标位置 HIWORD Y坐标位置
一般情况鼠标按下\抬起成对出现,在鼠标移动过程中,会根据移动速度产生一系列的WM_MOUSEMOVE消息
鼠标双击消息: wPARAM : 其他按键状态,例如Ctrl/Shift等 lPARAM : 鼠标的位置,窗口客户区坐标系 LOWORD X坐标位置 HIWORD Y坐标位置
消息产生顺序 以左键双击为例: WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONBLCLK WM_LBUTTONUP 使用时需要在注册窗口类的时候添加CS_DBLCLKS风格
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
鼠标滚轮消息: wPARAM: LOWORD - 其他按键状态 HIWORD - 滚轮的偏移量,通过正负值表示滚动方向,正:向前滚动 , 负:向后滚动 lPARAM:鼠标当前的位置,屏幕坐标系 LOWORD - X坐标系 HIWORD - Y坐标系
使用: 通过偏移量,获取滚动的方向和距离
3.定时器消息
定时器消息介绍: 产生时间: 在程序中创建定时器,当到达时间间隔时,定时器会向程序发送一个WM_TIMER消息。定时器的精度是毫秒,但是准确度很低。例如设置时间间隔为1000ms,但是会在非1000ms到达消息
附带信息: wPARAM: 定时器ID 了PARAM:定时器处理函数的指针
创建和销毁定时器: 创建定时器
//创建定时器
UINT_PTR SetTimer(
HWND hWnd,//定时器窗口句柄
UINT_PTR nIDEvent,//定时器ID
UINT uElapse,//时间间隔
TIMERPROC lpTimerFunc//定时器处理函数指针(一般不使用,为NULL)
)
//关闭定时器
BOOL KillTimer(
HWND hWnd,//定时器窗口句柄
UINT_PTR uIDEvent//定时器ID
)
尝试实现定时器:
//打印定时器函数
void on_Timer(HWND hwnd,WPARAM wParam)
{
wchar_t text[256] = {0};
wsprintf(text,L"定时器ID = %d",wParam);
WriteConsole(g_out, text, wcslen(text), NULL, NULL);
}
//当窗口创建时,创建两个定时器
case WM_CREATE:
SetTimer(hwnd, 1, 1000, NULL);//创建第一个定时器,ID:1,间隔:1S
SetTimer(hwnd, 2, 1000, NULL);//创建第一个定时器,ID:2,间隔:2S
定时器1每1s打印一次,定时器2每2s打印一次
4.菜单资源
1.菜单分类 · 窗口顶层菜单 · 弹出式菜单 · 系统菜单
HMENU(菜单句柄)类型表示菜单,ID表示菜单项
2.资源相关 资源脚本文件:.rc文件 编译器:RC.exe .rc–RC.exe–>.res .obj+.res–LINK.exe–>exe
3.菜单资源的使用 · 添加菜单资源 · 加载菜单资源 a.注册窗口类时设置菜单 b.创建窗口传参设置菜单 c.在主窗口WM_CREATE消息中利用SetMenu函数设置菜单
HMENU LoadMenu(
HINSTANCE hInstance,//
LPCTSTR lpMenuName
)
1.添加资源文件 2.在资源视图管理器中右击选择添加资源,选择menu资源 3.直接图形化开始编辑界面,可以在属性中修改菜单ID 4.挂菜单的三种方式
//注册窗口类时设置菜单
wc.lpszMenuName = (LPCWSTR)IDR_MENU1;
//在内存中创建窗口时
HMENU menu1 = LoadMenu(hInstance, (LPCWSTR)IDR_MENU1);//获取窗口句柄
HWND hwnd = CreateWindow((LPCWSTR)L"main", (LPCWSTR)L"hello world", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, menu1, hInstance, NULL);
//窗口处理函数里挂菜单
case WM_CREATE:
on_create(hwnd);
break;
//定义一个全局变量保存当前进程,以便访问
HINSTANCE g_hIn = 0;
void on_create(HWND hwnd)
{
HMENU Hmenu = LoadMenu(g_hIn, (LPCWSTR)IDR_MENU1);
SetMenu(hwnd, Hmenu);
}
完整代码:
#include
#include
#include "resource.h"
#define MY_MESS WM_USER + 100
HANDLE g_out = 0;
HINSTANCE g_hIn = 0;
void on_create(HWND hwnd)
{
HMENU Hmenu = LoadMenu(g_hIn, (LPCWSTR)IDR_MENU1);
SetMenu(hwnd, Hmenu);
}
LRESULT CALLBACK test(HWND hwnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
switch (msgID)
{
case WM_CREATE:
on_create(hwnd);
break;
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE)
{
if (MessageBox(hwnd, L"是否关闭?", L"infor", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
{
PostQuitMessage(0);
}
else
{
return 0;
}
}
break;
}
return DefWindowProc(hwnd, msgID, wParam, lParam);
}
int CALLBACK wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
g_hIn = hInstance;
AllocConsole();//增加dos窗口
g_out = GetStdHandle(STD_OUTPUT_HANDLE);
//注册窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0;//申请缓冲区
wc.cbWndExtra = 0;//申请缓冲区
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);//窗口背景色
wc.hCursor = NULL;//默认光标
wc.hIcon = NULL;//默认图标
wc.hInstance = hInstance;//实例句柄
wc.lpfnWndProc = test;//窗口处理函数
wc.lpszClassName = (LPCWSTR)L"main";//窗口类名称
wc.lpszMenuName = NULL;//不要菜单
//wc.lpszMenuName = (LPCWSTR)IDR_MENU1;
wc.style = CS_HREDRAW | CS_VREDRAW;//窗口水平或竖直方向有变化就重绘窗口
RegisterClass(&wc);//将以上所有赋值写入操作系统
//在内存中创建窗口
//HMENU menu1 = LoadMenu(g_hIn, (LPCWSTR)IDR_MENU1);
//HWND hwnd = CreateWindow((LPCWSTR)L"main", (LPCWSTR)L"hello world", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, menu1, hInstance, NULL);
HWND hwnd = CreateWindow((LPCWSTR)L"main", (LPCWSTR)L"hello world", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hInstance, NULL);
//显示窗口
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
//消息循环
MSG nMSG = { 0 };
while (GetMessage(&nMSG, NULL, 0, 0))
{
TranslateMessage(&nMSG);
DispatchMessage(&nMSG);//派发消息,将消息交给窗口处理函数处理
}
return 0;
}
4.命令消息处理
只要点击菜单项就会发送WM_COMMAND消息
WM_COMMAND: 附带信息: wPARAM: HIWORD - 对于菜单为0 LOWORD - 菜单项的ID IPARAM - 对于菜单为0
利用WM_COMMAND消息完成,尝试点退出弹出提示框
case WM_COMMAND:
ON_COM(hwnd, wParam);
break;
void ON_COM(HWND hwnd, WPARAM wParam)
{
if (LOWORD(wParam) == ID_OUT&&MessageBox(hwnd, L"是否关闭?", L"infor", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
{
PostQuitMessage(0);
}
}
完整代码:
#include
#include
#include "resource.h"
void ON_COM(HWND hwnd, WPARAM wParam)
{
if (LOWORD(wParam) == ID_OUT&&MessageBox(hwnd, L"是否关闭?", L"infor", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
{
PostQuitMessage(0);
}
}
LRESULT CALLBACK test(HWND hwnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
switch (msgID)
{
case WM_COMMAND:
ON_COM(hwnd, wParam);
break;
}
return DefWindowProc(hwnd, msgID, wParam, lParam);
}
int CALLBACK wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
//注册窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0;//申请缓冲区
wc.cbWndExtra = 0;//申请缓冲区
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);//窗口背景色
wc.hCursor = NULL;//默认光标
wc.hIcon = NULL;//默认图标
wc.hInstance = hInstance;//实例句柄
wc.lpfnWndProc = test;//窗口处理函数
wc.lpszClassName = (LPCWSTR)L"main";//窗口类名称
//wc.lpszMenuName = NULL;//不要菜单
wc.lpszMenuName = (LPCWSTR)IDR_MENU1;
wc.style = CS_HREDRAW | CS_VREDRAW;//窗口水平或竖直方向有变化就重绘窗口
RegisterClass(&wc);//将以上所有赋值写入操作系统
//在内存中创建窗口
//HMENU menu1 = LoadMenu(g_hIn, (LPCWSTR)IDR_MENU1);
//HWND hwnd = CreateWindow((LPCWSTR)L"main", (LPCWSTR)L"hello world", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, menu1, hInstance, NULL);
HWND hwnd = CreateWindow((LPCWSTR)L"main", (LPCWSTR)L"hello world", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hInstance, NULL);
//显示窗口
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
//消息循环
MSG nMSG = { 0 };
while (GetMessage(&nMSG, NULL, 0, 0))
{
TranslateMessage(&nMSG);
DispatchMessage(&nMSG);//派发消息,将消息交给窗口处理函数处理
}
return 0;
}
5.上下文菜单
· 现实上下文菜单
BOOL TrackPopupMenu(
HMENU hMenu,//菜单句柄
UINT uFlags,//现实方式
int x,//水平位置,屏幕坐标系
int y,//垂直位置,屏幕坐标系
int nReserved,//保留,必须0
HWND hWnd,//处理菜单消息的窗口句柄
CONST RECT *prcRect//NULL,忽略
)//是阻塞函数
void ON_CONTEXT(HWND hwnd, LPARAM lParam)
{
HMENU MainMenu = LoadMenu(G_HINS, (LPCWSTR)IDR_MENU1);
HMENU HPop = GetSubMenu(MainMenu, 0);//获得自菜单函数
TrackPopupMenu(HPop, TPM_CENTERALIGN | TPM_VCENTERALIGN, LOWORD(lParam), HIWORD(lParam), 0, hwnd, NULL);
}
LRESULT CALLBACK test(HWND hwnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
switch (msgID)
{
case WM_COMMAND:
ON_COM(hwnd, wParam);
break;
case WM_CONTEXTMENU://上下文弹出菜单的专门消息
ON_CONTEXT(hwnd, lParam);
break;
}
return DefWindowProc(hwnd, msgID, wParam, lParam);
}
WM_CONTEXTMENU:
wPARAM:右键点击的窗口句柄 lPARAM:LOWORD X坐标,屏幕坐标系;HIWORD Y坐标,屏幕坐标系
WM_CONTEXTMENU消息是在WM_RBUTTONUP消息之后产生的
TPM_CENTERALIGN | TPM_VCENTERALIGN是鼠标在弹出菜单的位置,此时设置的是菜单正中心,一般是TPM_LEFTALIGN | TPM_TOPALIGN在菜单左上角
运行效果: 在这里插入图片描述