zoukankan      html  css  js  c++  java
  • win32程序之子窗口编程

                  win32程序之子窗口编程

    一丶简介.什么是子窗口

      在前边我们已经讲解了窗口的本质.以及如何注册窗口类跟创建窗口. 还讲了消息循环.

    那么有很多窗口其实Windows已经帮我们创建出来了.我们直接使用即可. 而这些窗口都有自己的消息循环. 只有改变状态的时候.才会发送消息给我们的父窗口通知.

    此时我们捕获消息就可以进行处理了.

    子窗口其实就是绘制在主窗口的一个窗口.  这些窗口包含了  BUTTON  (按钮控件)  EDIT(编辑框控件) .....

    二丶创建子窗口

    1.创建EDIT子窗口

      创建子窗口很简单. 使用CreteWindow API. 类名修改为EDIT. 父窗口句柄修改为我们的主窗口句柄.  并且为子窗口设置创建类型.  以及子窗口标识符即可.

    具体代码如下: 当主窗口创建消息来得时候.我们创建一个EDIT编辑框.

    // WindoS.cpp : 定义应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include "WindoS.h"
    
    #define MAX_LOADSTRING 100
    
    // 全局变量: 
    HINSTANCE g_hInst;                                // 当前实例
    WCHAR szTitle[MAX_LOADSTRING]  = TEXT("第一个我的窗口");                  // 标题栏文本
    WCHAR szWindowClass[MAX_LOADSTRING] = TEXT("MyWindow");            // 主窗口类名
    #define IDC_MY_EDIT_ONE 10  //编辑框的ID 自己定义即可.
    // 此代码模块中包含的函数的前向声明: 
    
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        //1.自定义窗口样式
        g_hInst = hInstance;
        WNDCLASS wcex;
    
    
        wcex.style = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc = WndProc;                          //设置回调
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = hInstance;
        wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOS));
        wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOS);
        wcex.lpszClassName = szWindowClass;
        
        //2.注册窗口类
        BOOL bRet = RegisterClass(&wcex); //A RegisterClass U RegisterClassW  扩展 RegisterClassExA /ExW
        if (bRet == FALSE)
        {
            return 0;
        }
        //3.创建窗口 并且显示跟更新窗口
        HWND hWnd = CreateWindowW(
            szWindowClass,
            szTitle,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            0,
            CW_USEDEFAULT,
            0, 
            nullptr,
            nullptr,
            hInstance,
            nullptr);
    
        if (!hWnd)
        {
            return FALSE;
        }
    
        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);
    
        //4.消息循环.
        MSG msg;
        /*    1参数是消息结构体.操作系统会往里面填写消息. 
            2 参数窗口句柄 因为每个线程可以有多个窗口.表示我要取那个窗口的消息
            3.4 参数表示我要取这个窗口的那个消息. 后面三个参数属于过滤条件
    
    
        */
        while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)        
        {
            if (bRet == -1)
            {
                // handle the error and possibly exit
            }
            else
            {
                TranslateMessage(&msg);      //键盘消息转换为小写.
                DispatchMessage(&msg);      //分发消息.将我们的消息传递给我们的回调函数处理.
            }
        }
    
        return 0;
    }
    
    
    
    
    
    
    //
    //  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  目的:    处理主窗口的消息。
    //
    //  WM_COMMAND  - 处理应用程序菜单
    //  WM_PAINT    - 绘制主窗口
    //  WM_DESTROY  - 发送退出消息并返回
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_CREATE:
        {
             CreateWindowW(                                    //创建编辑框
                TEXT("EDIT"),
                TEXT("编辑框所处位置"),
                WS_CHILD | WS_VISIBLE | WS_VSCROLL, //前3个是通用风格.EDIT风格搜索MSDN 搜索Edit Style即可.
                10,10,800,400,             //设置X Y 坐标.设置高度跟宽度.
                 hWnd,                    //父类句柄
                (HMENU)IDC_MY_EDIT_ONE,
                g_hInst,
                nullptr);
            break;
        }
        case WM_COMMAND:
            {
                int wmId = LOWORD(wParam);
                // 分析菜单选择: 
                switch (wmId)
                {
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
                }
            }
            break;
        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hWnd, &ps);
                // TODO: 在此处添加使用 hdc 的任何绘图代码...
                
                EndPaint(hWnd, &ps);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }

    上面红色的那块是很重要的. 重要参数标注出来.

    1.窗口类名. 我们是使用的Windows默认的窗口类名.所以填写EDIT

    2.窗口风格. 窗口风格是使用的CreateWindow 中MSDN提供的默认风格. 当然编辑框也有自己的风格.我们可以MSDN搜寻 EDIT styles 查看说明.

    3.父窗口句柄. 因为这个是创建在父窗口的所以我们的父窗口句柄一定要填写.

    4.实例句柄.这个必须要填写的.已经改成全局变量了.

    5.编辑框的ID.编辑框的ID属于是控件ID. 这个位置在MSDN有说明. 如果创建的是父窗口.这个地方填写的则是菜单.也就是HMENU类型的.但是如果是子窗口.那么这个位置就变成了控件ID了.

    具体可以查看MSDN说明. 这个控件ID很重要.关乎到我们处理消息.

    2.创建按钮子窗口

      上面创建了EDIT.那我们也可以创建按钮子窗口了.具体代码跟创建EDIT位置处一样.

         CreateWindowW(                                    //创建按钮
                 TEXT("BUTTON"),
                 TEXT("设置"),
                 WS_CHILD | WS_VISIBLE, //
                 820, 30, 100, 40,             //设置X Y 坐标.设置高度跟宽度.
                 hWnd,                    //父类句柄
                 (HMENU)IDC_MY_BUTTON_ONE,
                 g_hInst,
                 nullptr);
    
    
             CreateWindowW(                                    //创建按钮
                 TEXT("BUTTON"),
                 TEXT("获取"),
                 WS_CHILD | WS_VISIBLE, //
                 820, 80, 100, 40,             //设置X Y 坐标.设置高度跟宽度.
                 hWnd,                    //父类句柄
                 (HMENU)IDC_MY_BUTTON_TWO,
                 g_hInst,
                 nullptr);

    这两行代码放到创建EDIT下面即可.

    关于按钮的ID.我们设置一个自定义的整数值即可. 使用的时候需要强转为HMENU类型.

    结果演示.

     三丶响应子窗口的消息.

      现在我们已经创建完毕子窗口了.那么我们想的是我要响应按钮消息什么的.

    Windows虽然为每个子控件提供了消息处理函数. 也就是回调. 但是Windows为了让我们处理消息. 所以子窗口有一个特性. 就是说当改变状态的时候.会通知父窗口.

    怎么理解.什么意思?  意思就是说.当我们点击这个按钮的时候.windows会发给我们父窗口一个消息. 我们只需要接受这个消息即可. 但是我们如何知道是哪个消息.?

    既然我们知道了子窗口改变状态会发送消息.那么我们可以调试一下.打印一下消息.

    也就是在我们父窗口的消息处理回调中打印一下消息. 使用DebugView查看.或者调试查看都可以. 

    因为当我们点击才会出现这个消息.那么我们可以看下这个消息是什么消息.

    我们可以随便点击一个消息.查看定义.即可看到Windows全部的消息了.  windows消息都放在了WinUser.h中

    可以看到通知父窗口的是WM_COMMAND消息.

    所以我们直接捕获这个消息进行处理即可.

    查询MSDN 查询WM_COMMAND消息.

    详细说明了.如果是WM_COMMAND消息. 那么参数三是控件ID.  还记得上面我们说的吗. 要给每个控件分配一个控件ID. 就是在这里使用的.

    具体看参数就如上图所示. 告诉你了.低位才是 ID. 也就是 menu item标记. 所以我们需要取低位来判断. 因为WPARAME 是32位.所以低位是16位.

    我们可以自己使用位运算取.也可以使用操作系统提供的  LOWORD 来取.

    具体代码如下图所示.  PS: 直接拷贝窗口回调函数了.

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	
    
        switch (message)
        {
    	case WM_CREATE:
    	{
    		 CreateWindowW(									//创建编辑框
    			TEXT("EDIT"),
    			TEXT("编辑框所处位置"),
    			WS_CHILD | WS_VISIBLE | WS_VSCROLL, //前3个是通用风格.EDIT风格搜索MSDN 搜索Edit Style即可.
    			10,10,800,400,             //设置X Y 坐标.设置高度跟宽度.
    			 hWnd,					//父类句柄
    			(HMENU)IDC_MY_EDIT_ONE,
    			g_hInst,
    			nullptr);
    
    		 CreateWindowW(									//创建按钮
    			 TEXT("BUTTON"),
    			 TEXT("设置"),
    			 WS_CHILD | WS_VISIBLE, //
    			 820, 30, 100, 40,             //设置X Y 坐标.设置高度跟宽度.
    			 hWnd,					//父类句柄
    			 (HMENU)IDC_MY_BUTTON_ONE,
    			 g_hInst,
    			 nullptr);
    
    
    		 CreateWindowW(									//创建按钮
    			 TEXT("BUTTON"),
    			 TEXT("获取"),
    			 WS_CHILD | WS_VISIBLE, //
    			 820, 80, 100, 40,             //设置X Y 坐标.设置高度跟宽度.
    			 hWnd,					//父类句柄
    			 (HMENU)IDC_MY_BUTTON_TWO,
    			 g_hInst,
    			 nullptr);
    
    
    		break;
    	}
        case WM_COMMAND:                               //获取Command消息. 取出低位ID. 根据ID进行不同的操作.
            {
                int wmId = LOWORD(wParam);
                // 分析菜单选择: 
                switch (wmId)
                {
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
    			case IDC_MY_BUTTON_ONE:    //按钮设置点击则回来
    			{
    				 //这个ID是按钮设置的ID.所以当按钮设置就会来这里了.
    				SetDlgItemText(hWnd, IDC_MY_EDIT_ONE, TEXT("设置到编辑框的内容"));  //此API时设置指定窗口中控件ID的显示名称.我们给编辑框设置.所以ID是编辑框的ID.
    				break;
    			}
    			case IDC_MY_BUTTON_TWO:
    			{
    				// ID同上所示
    				TCHAR str[1024] = { NULL };
    				GetDlgItemText(hWnd, IDC_MY_EDIT_ONE, str, sizeof(str));        //有设置就有获取. 获取就是需要提供缓冲区而已.然后Msg信息框弹出.
    				MessageBox(hWnd, str, NULL, NULL);
    				break;
    			}
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
                }
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    } 

    最终实现结果.

    点击设置后.编辑框的内容会改变.

     点击获取后则会获取编辑框的内容.

    四丶完整代码.

    最后附上完整代码.拷贝就能使用. VS2015编写.不确定是否可以.不过可以参考代码.

    代码如下:

    // WindoS.cpp : 定义应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include "WindoS.h"
    
    #define MAX_LOADSTRING 100
    
    // 全局变量: 
    HINSTANCE g_hInst;                                // 当前实例
    WCHAR szTitle[MAX_LOADSTRING]  = TEXT("第一个我的窗口");                  // 标题栏文本
    WCHAR szWindowClass[MAX_LOADSTRING] = TEXT("MyWindow");            // 主窗口类名
    #define IDC_MY_EDIT_ONE 10  //编辑框的ID 自己定义即可.
    #define IDC_MY_BUTTON_ONE 11
    #define IDC_MY_BUTTON_TWO 12
    // 此代码模块中包含的函数的前向声明: 
    
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
    	//1.自定义窗口样式
    	g_hInst = hInstance;
    	WNDCLASS wcex;
    
    
    	wcex.style = CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc = WndProc;                          //设置回调
    	wcex.cbClsExtra = 0;
    	wcex.cbWndExtra = 0;
    	wcex.hInstance = hInstance;
    	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOS));
    	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOS);
    	wcex.lpszClassName = szWindowClass;
    	
    	//2.注册窗口类
    	BOOL bRet = RegisterClass(&wcex); //A RegisterClass U RegisterClassW  扩展 RegisterClassExA /ExW
    	if (bRet == FALSE)
    	{
    		return 0;
    	}
    	//3.创建窗口 并且显示跟更新窗口
    	HWND hWnd = CreateWindowW(
    		szWindowClass,
    		szTitle,
    		WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT,
    		0,
    		CW_USEDEFAULT,
    		0, 
    		nullptr,
    		nullptr,
    		hInstance,
    		nullptr);
    
    	if (!hWnd)
    	{
    		return FALSE;
    	}
    
    	ShowWindow(hWnd, SW_SHOW);
    	UpdateWindow(hWnd);
    
    	//4.消息循环.
    	MSG msg;
    	/*	1参数是消息结构体.操作系统会往里面填写消息. 
    		2 参数窗口句柄 因为每个线程可以有多个窗口.表示我要取那个窗口的消息
    		3.4 参数表示我要取这个窗口的那个消息. 后面三个参数属于过滤条件
    
    
    	*/
    	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)        
    	{
    		if (bRet == -1)
    		{
    			// handle the error and possibly exit
    		}
    		else
    		{
    			TranslateMessage(&msg);      //键盘消息转换为小写.
    			DispatchMessage(&msg);      //分发消息.将我们的消息传递给我们的回调函数处理.
    		}
    	}
    
    	return 0;
    }
    
    
    
    
    
    
    //
    //  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  目的:    处理主窗口的消息。
    //
    //  WM_COMMAND  - 处理应用程序菜单
    //  WM_PAINT    - 绘制主窗口
    //  WM_DESTROY  - 发送退出消息并返回
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	
    
        switch (message)
        {
    	case WM_CREATE:
    	{
    		 CreateWindowW(									//创建编辑框
    			TEXT("EDIT"),
    			TEXT("编辑框所处位置"),
    			WS_CHILD | WS_VISIBLE | WS_VSCROLL, //前3个是通用风格.EDIT风格搜索MSDN 搜索Edit Style即可.
    			10,10,800,400,             //设置X Y 坐标.设置高度跟宽度.
    			 hWnd,					//父类句柄
    			(HMENU)IDC_MY_EDIT_ONE,
    			g_hInst,
    			nullptr);
    
    		 CreateWindowW(									//创建按钮
    			 TEXT("BUTTON"),
    			 TEXT("设置"),
    			 WS_CHILD | WS_VISIBLE, //
    			 820, 30, 100, 40,             //设置X Y 坐标.设置高度跟宽度.
    			 hWnd,					//父类句柄
    			 (HMENU)IDC_MY_BUTTON_ONE,
    			 g_hInst,
    			 nullptr);
    
    
    		 CreateWindowW(									//创建按钮
    			 TEXT("BUTTON"),
    			 TEXT("获取"),
    			 WS_CHILD | WS_VISIBLE, //
    			 820, 80, 100, 40,             //设置X Y 坐标.设置高度跟宽度.
    			 hWnd,					//父类句柄
    			 (HMENU)IDC_MY_BUTTON_TWO,
    			 g_hInst,
    			 nullptr);
    
    
    		break;
    	}
        case WM_COMMAND:
            {
                int wmId = LOWORD(wParam);
                // 分析菜单选择: 
                switch (wmId)
                {
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
    			case IDC_MY_BUTTON_ONE:
    			{
    				 //这个ID是按钮设置的ID.所以当按钮设置就会来这里了.
    				SetDlgItemText(hWnd, IDC_MY_EDIT_ONE, TEXT("设置到编辑框的内容"));
    				break;
    			}
    			case IDC_MY_BUTTON_TWO:
    			{
    				// ID同上所示
    				TCHAR str[1024] = { NULL };
    				GetDlgItemText(hWnd, IDC_MY_EDIT_ONE, str, sizeof(str));
    				MessageBox(hWnd, str, NULL, NULL);
    				break;
    			}
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
                }
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    

      

  • 相关阅读:
    Springboot~多个数据源时自定义datasource的bean
    springboot~aspose操作word模板实现导出功能
    spring-security-jwt的总结与实现
    mybatis+maven自动生成代码框架
    chrome 插件 vimium 像操作vim一样的操作浏览器
    递归计算过程和迭代计算过程
    找工作--Java相关
    《Linux程序设计》--读书笔记---第十三章进程间通信:管道
    poj 1474 Video Surveillance
    动态包含与静态包含的区别
  • 原文地址:https://www.cnblogs.com/iBinary/p/9581252.html
Copyright © 2011-2022 走看看