IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 03 发送消息自定义消息模态对话框 -> 正文阅读

[C++知识库]03 发送消息自定义消息模态对话框

03 windows编程3 发送消息 自定义消息 模态对话框

课程内容

  • 发送消息
  • 自定义消息
  • 模态对话框

课程详情

发送消息

方法一:SendMessage
函数原型:
LRESULT WINAPI SendMessage(
  _In_  HWND hWnd,
  _In_  UINT Msg,
  _In_  WPARAM wParam,
  _In_  LPARAM lParam
);
参数说明:
参数名参数类型参数说明
hWndHWND窗口句柄,指明要发送的消息进入哪个窗口的消息队列
MsgUINT消息的编号
wParamWPARAM消息附加信息1
lParamLPARAM消息附加信息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;
}
运行效果:

img

方法二: PostMessage
函数原型
BOOL WINAPI PostMessage(
  _In_opt_  HWND hWnd,
  _In_      UINT Msg,
  _In_      WPARAM wParam,
  _In_      LPARAM lParam
);
参数说明:
参数名参数类型参数说明
hWndHWND窗口句柄,指明要发送的消息进入哪个窗口的消息队列
MsgUINT消息的编号
wParamWPARAM消息附加信息1
lParamLPARAM消息附加信息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;
}

img

说明:

因为是非阻塞的,因此,在循环条件中,如果不加延时,会造成在窗口关闭前不停的发送消息,导致计数不准确的情况.

自定义消息

首先, 消息的本质是一个整数,因此,自定义消息本质是将一个事件(消息)与一个整数进行绑定,为了避免与其他消息造成冲突,我们需要将自定义消息所绑定的整数是与其他消息不同的,即一个整数绑定一个消息.

系统定义了自定义消息的基础整数宏:

因此,自定义消息的步骤如下:

  1. 定义一个宏来绑定消息整数.
#define UM_MESSAGE1 WM_UESR + 1
#define UM_MESSAGE2 UM_MESSAGE + 1

为了与系统的消息做区别,自定义消息的整数应该排在WM_USER之后.

这里选择了+1, 加多少随意,只要不重复就可了

多个消息,可以依次往下排

  1. 自定义附加消息的含义

即自定义wParam, lParam两个参数的意义

  1. 自定义消息发送的时机

应该有计划的理解什么时候可以发送消息,如果对返回值有要求,也要考虑用哪一种方式进行发送消息

示例一:

按下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;
}

运行效果:

img

示例二:

当按下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;
}

运行效果:

img

模态对话框

模态对话框与非模态对话框的区别:

在一个应用程序中, 当我们打开一个模态对话框时, 如果不关闭这个窗口,其他的窗口将无法再获取焦点进行操作

当我们打开一个非模态的对话框时,程序的其他窗口不受影响,仍然可以正常获取焦点进行操作

构造模态对话框

创建一个模态对话框

第一步: 添加资源

img

img

第二步: 修改对话框ID

在属性管理器中找到ID这一栏

img

改一个好理解的名字

第三步: 调用函数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;
}

运行效果

窗口标题与图标

img

切换窗口时的图标

img

关闭模式对话框

在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菜单项的ID0
Accelerator(快捷键)1快捷键的ID0
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;
}

聊天对话框运行效果

img

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-27 11:09:20  更:2022-04-27 11:09:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 20:41:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码