03 windows编程3 发送消息 自定义消息 模态对话框
课程内容
课程详情
发送消息
方法一:SendMessage
函数原型:
LRESULT WINAPI SendMessage(
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
参数说明:
参数名 | 参数类型 | 参数说明 |
---|
hWnd | HWND | 窗口句柄,指明要发送的消息进入哪个窗口的消息队列 | Msg | UINT | 消息的编号 | wParam | WPARAM | 消息附加信息1 | lParam | LPARAM | 消息附加信息2 |
返回值:
类型: LRESULT
含义:消息处的结果 即消息处理函数的返回值
注意: 该函数以阻塞的方式将消息发送到消息队列.
如果用此方法发送消息,会导致进程阻塞,只到消息处理完毕,才会继续下去.因此,此方法一般应用于同进程的消息发送
示例:
当我们按下鼠标右键的时候,发送一个WM_KEYDOWN消息, 附加消息等价于按了A键
//第一步: 处理右键消息
case WM_RBUTTONDOWN:
{
LRESULT n = SendMessage(hWnd, WM_KEYDOWN, 0x041, 0);
wchar_t szResult[100];
wsprintf(szResult, L"返回值为%d", n);
MessageBox(hWnd, szResult, L"提示", MB_OK);
break;
}
//第二步: 按键消息处理
case WM_KEYDOWN:
{
switch (wParam)
{
case 0x041:
SetWindowText(hWnd, L"字母a键消");
return 10;
break;
}
break;
}
运行效果:
方法二: PostMessage
函数原型
BOOL WINAPI PostMessage(
_In_opt_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
参数说明:
参数名 | 参数类型 | 参数说明 |
---|
hWnd | HWND | 窗口句柄,指明要发送的消息进入哪个窗口的消息队列 | Msg | UINT | 消息的编号 | wParam | WPARAM | 消息附加信息1 | lParam | LPARAM | 消息附加信息2 |
返回值说明:
类型: BOOL
含义: 消息发送成功与否,成功为非0,否则为0
说明: 本函数发送消息不会阻塞消息队列,因此只关注消息有没有发送成功,不关注消息的处理结果
因此,一般此方法用于不同的进程间的消息发送
示例:
如果鼠标左键点击,则查找系统中有没有运行"记事本"软件,如果有,则关闭所有的记事本软件,并弹窗显示关闭的个数
如果没有个数为0
case WM_LBUTTONDOWN: // 鼠标左键消息处理
{
int nCount = 0; //初始化计数器
HWND hNotePad = FindWindow(L"Notepad", NULL); //用窗口类名查找"记事本"的窗口句柄
while (hNotePad)
{
PostMessage(hNotePad, WM_CLOSE, 0, 0); //如果句柄不为空,则向该窗口发送关闭窗口消息
Sleep(100); //暂停100ms,以免发送速度过快来不及关闭
nCount ++;
hNotePad = FindWindow(L"Notepad", NULL);//再次查找窗口句柄
}
wchar_t szInfo[100];
wsprintf(szInfo, L"关闭了%d个记事本窗口", nCount);
MessageBox(hWnd, szInfo, L"关闭结果", MB_OK);
break;
}
说明:
因为是非阻塞的,因此,在循环条件中,如果不加延时,会造成在窗口关闭前不停的发送消息,导致计数不准确的情况.
自定义消息
首先, 消息的本质是一个整数,因此,自定义消息本质是将一个事件(消息)与一个整数进行绑定,为了避免与其他消息造成冲突,我们需要将自定义消息所绑定的整数是与其他消息不同的,即一个整数绑定一个消息.
系统定义了自定义消息的基础整数宏:
因此,自定义消息的步骤如下:
- 定义一个宏来绑定消息整数.
#define UM_MESSAGE1 WM_UESR + 1
#define UM_MESSAGE2 UM_MESSAGE + 1
为了与系统的消息做区别,自定义消息的整数应该排在WM_USER之后.
这里选择了+1, 加多少随意,只要不重复就可了
多个消息,可以依次往下排
- 自定义附加消息的含义
即自定义wParam, lParam两个参数的意义
- 自定义消息发送的时机
应该有计划的理解什么时候可以发送消息,如果对返回值有要求,也要考虑用哪一种方式进行发送消息
示例一:
按下Ctrl + C 时发送一个复制的消息
消息名: UM_COPY
wParam参数作用: 起点索引
lParam参数作用: 终点过引
示例代码:
//第一步: 定义UM_COPY宏
#define UM_COPY WM_USER + 1
//第二步: 触发逻辑
case 0X41 + 2: // Ctrl + C 消息处理
{
BOOL bCtrl = GetKeyState(VK_CONTROL) < 0;
if (bCtrl)
{
PostMessage(hWnd, UM_COPY, 0, 10);
}
break;
}
//第三步:自定义消息的处理
case UM_COPY:
{
int nStart = (int)wParam;
int nEnd = (int)lParam;
//假装可以获到这个字符串内容
WCHAR szText[100];
wsprintf(szText, L"复制的内容从%d到%d", (int)wParam, (int)lParam);
MessageBox(hWnd, szText, l"复制", MB_OK);
break;
}
运行效果:
示例二:
当按下Ctrl + V时,弹出对话框,输出一个结构体的中的字段
结构体
struct STU
{
wchar_t name[20]; //姓名
int age; //年龄
};
消息名:UM_PAST
wParam: 一个STU结构体指针
lParam: 无
返回值: 无
示例代码:
//第一步: 绑定消息整数
#define UM_PAST UM_COPY + 1
//第二步: 发送UM_PAST消息
case 0x41 + 'v' - 'a':
{
BOOL bCtrl = GetKeyState(VK_CONTROL) < 0;
if (bCtrl)
{
STU * stu = new STU;
wsprintf(stu->name, L"张三");
stu->age = 20;
PostMessage(hWnd, UM_PAST, (WPARAM)stu, 0);
}
break;
}
//第三步: 处理消息
case UM_PAST:
{
WCHAR szStuInfo[200];
STU *stu = (STU *)wParam;
wsprintf(szStuInfo, L"姓名%s, 年龄%d", stu->name, stu->age);
MessageBox(hWnd, szStuInfo, L"粘贴结果", MB_OK);
break;
}
运行效果:
模态对话框
模态对话框与非模态对话框的区别:
在一个应用程序中, 当我们打开一个模态对话框时, 如果不关闭这个窗口,其他的窗口将无法再获取焦点进行操作
当我们打开一个非模态的对话框时,程序的其他窗口不受影响,仍然可以正常获取焦点进行操作
构造模态对话框
创建一个模态对话框
第一步: 添加资源
第二步: 修改对话框ID
在属性管理器中找到ID这一栏
改一个好理解的名字
第三步: 调用函数DialogBox
函数原型
INT_PTR WINAPI DialogBox(
_In_opt_ HINSTANCE hInstance,
_In_ LPCTSTR lpTemplate,
_In_opt_ HWND hWndParent,
_In_opt_ DLGPROC lpDialogFunc
);
参数说明:
第一个参数: 对话框所属应用程序实例句柄
第二个参数: 对话框的ID, 要用MAKEINTRESOURCE 转成LPCSTR
第三个参数: 对话框的父窗体
第四个参数: 对话框的消息处理函数
返回值: 模态对话框关闭时的返回值
因为模态对话框是阻塞的,因此该函数的返回值是窗口关闭时传过来的值
可以根据这个值进行后续的操作
注意: 消息处理函数的返回值必须是 FALSE(0), 否则在运行时会出BUG
模态对话框的初始化消息
消息名称: WM_INITDIALOG
可以在这个消息里进行对话框初始的相关操作
示例代码
case WM_INITDIALOG:
{
//设置窗口标题
SetWindowText(hWnd, L"登陆");
HICON hIconBig = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON_BIG));
HICON hIconSmall = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON_SMALL));
PostMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIconBig); //设置图标
PostMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall); //设置图标
break;
}
运行效果
窗口标题与图标
切换窗口时的图标
关闭模式对话框
在WM_CLOSE消息中调用EndDialog函数
函数原型:
BOOL WINAPI EndDialog(
_In_ HWND hDlg,
_In_ INT_PTR nResult
);
参数说明:
第一个参数: 要关闭的对话框句柄
第二个参数: 最终DialogBox函数的返回值的值
函数作用:
关闭对话框窗口
示例代码:
case WM_CLOSE:
{
EndDialog(hWnd, IDCANCEL);
break;
}
按钮的点击响应
消息名称: WM_COMMAND
附加信息参数说明:
事件发送者 | wParam高位取值 | wParam低位取值 | lParar |
---|
Menu(菜单) | 0 | 菜单项的ID | 0 | Accelerator(快捷键) | 1 | 快捷键的ID | 0 | Control(控件) | 控件ID | | 控件窗口句柄 |
示例一: 退出按钮响应
case WM_COMMAND:
{
if (wParam == ID_EXIT_BTN)
{
PostMessage(hWnd, WM_CLOSE, 0, 0 );
break;
}
}
示例二: 登陆按钮响应
else if (wParam == ID_LOGIN_BTN)
{
wchar_t szUserName[100];
wchar_t szPassWord[100];
GetDlgItemText(hWnd, IDC_NAME_EDIT, szUserName, 100);
GetDlgItemText(hWnd, IDC_PASSWORD_EDIT, szPassWord, 100);
if (wcscmp(szUserName, L"admin") && wcscmp(szPassWord, L"123456"))
{
EndDialog(hWnd, IDOK);//关闭对话框,并返回IDOK说明登陆成功
}
else
{
MessageBox(hWnd, L"用户名或密码有误", L"登陆失败", MB_OK);//密码错误给出提示
}
break;
}
设置模态对话框图标
消息名: WM_SETICON
消息附加参数说明:
wParam: 标识窗口左上角的图还是Alt+Tab键切换程序时显示的窗口图标
取值: ICON_BIG(切换窗口时的图标) 和ICON_SMALL(窗口左上角图标)
lParam: 图标资源的句柄
WM_SETICON不需要手动处理,只需发送消息即可
示例代码
PostMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIconBig); //设置图标
PostMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall); //设置图标
非模态对话框
创建非模态对话框
函数: CreateDialog
函数原型
HWND WINAPI CreateDialog(
_In_opt_ HINSTANCE hInstance,
_In_ LPCTSTR lpTemplate,
_In_opt_ HWND hWndParent,
_In_opt_ DLGPROC lpDialogFunc
);
参数说明:
第一个参数: 应用程序实例句柄
第二个参数: 窗口模板(窗口资源ID)
第三个参数: 父窗口句柄
第四个参数: 消息处理函数
返回值: 窗口实例句柄
关闭非模态对话框
函数: DestroyDialog
函数原型
BOOL WINAPI DestroyWindow(
_In_ HWND hWnd
);
参数说明:
要关闭的窗口实例句柄
返回值:
关闭成功返回非0,否则返回0
隐藏非模态对话框
函数: EndDialog
完整示例代码
#include<Windows.h>
#include "resource.h"
//定义全局变量
HINSTANCE g_hInstance; //应用程序实例句柄
//登陆对话框的消息处理函数
BOOL CALLBACK LoginDlgPro(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//程序主窗口消息处理函数
BOOL CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//聊天窗口消息处理函数
BOOL CALLBACK ChatProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//主程序入口函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdline, int nCmdShow)
{
g_hInstance = hInstance;
int nResult = DialogBox(hInstance, MAKEINTRESOURCE(IDD_LOGIN_DLG),NULL, LoginDlgPro);
if (nResult == IDOK) //判断是否登陆成功
{
//登陆成功进入主窗口
DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAINWND_DLG), NULL, MainWndProc);
}
return 0;
}
//登陆窗口消息处理函数
BOOL CALLBACK LoginDlgPro(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
SetWindowText(hWnd, L"登陆");
HICON hIconBig = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON_BIG));
HICON hIconSmall = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON_SMALL));
PostMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIconBig);
PostMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall);
break;
}
case WM_CLOSE:
{
EndDialog(hWnd, IDCANCEL);
break;
}
case WM_COMMAND:
{
if (wParam == ID_EXIT_BTN)
{
int nResult = MessageBox(hWnd, L"确定要退出么?", L"退出",MB_YESNO);
if (nResult == IDYES)
{
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
break;
}
else if (wParam == ID_LOGIN_BTN)
{
wchar_t szUserName[100];
wchar_t szPassWord[100];
GetDlgItemText(hWnd, IDC_NAME_EDIT, szUserName, 100);
GetDlgItemText(hWnd, IDC_PASSWORD_EDIT, szPassWord, 100);
if (wcscmp(szUserName, L"admin") == 0 && wcscmp(szPassWord, L"123456") == 0)
{
EndDialog(hWnd, IDOK);
}
else
{
MessageBox(hWnd, L"用户名或密码有误", L"登陆失败", MB_OK);
}
break;
}
}
}
return FALSE;
}
//主程序窗口消息处理函数
BOOL CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
{
EndDialog(hWnd, IDCANCEL);
break;
}
case WM_INITDIALOG:
{
SetWindowText(hWnd, L"主窗口");
}
case WM_COMMAND:
{
switch (wParam)
{
case ID_EXIT_BTN_MW:
PostMessage(hWnd, WM_CLOSE,0 ,0);
break;
case ID_ABOUT_BTN_MW:
MessageBox(hWnd, L"本程序由少儿编程章开发", L"关于", MB_OK);
break;
case IDC_CHAT_BTN:
{
HWND hChatDlg = CreateDialog(g_hInstance, (LPCWSTR)IDD_CHAT_DLG, hWnd, ChatProc);
ShowWindow(hChatDlg, SW_SHOW);
UpdateWindow(hChatDlg);
break;
}
}
}
}
return FALSE;
}
//聊天窗口消息处理函数
BOOL CALLBACK ChatProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE: //关闭窗口消息处理
DestroyWindow(hWnd);
break;
case WM_COMMAND: //按钮消息处理
{
if (wParam == ID_SEND_BTN) //发送按钮
{
wchar_t szHistoryText[10000];
GetDlgItemText(hWnd, IDC_HISTROYCHAT_EDIT, szHistoryText, 10000);
wchar_t szMessage[1000];
GetDlgItemText(hWnd, IDC_MESSAGE_EDIT, szMessage, 1000);
if (wcslen(szMessage) > 0) //消息编辑框非空,则加入历史消息框
{
if (wcslen(szHistoryText) > 0) //历史消息非空,则换行
wcscat(szHistoryText, L"\r\n");
wcscat(szHistoryText, szMessage); //将消息框的内容加入历史消息
SetDlgItemText(hWnd, IDC_HISTROYCHAT_EDIT, szHistoryText);
SetDlgItemText(hWnd, IDC_MESSAGE_EDIT, L"");
UpdateWindow(hWnd);//更新窗口
}
break;
}
break;
}
}
return FALSE;
}
聊天对话框运行效果
|