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 = ;
wcex.cbWndExtra = ;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOS));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOS);
wcex.lpszClassName = szWindowClass; //2.注册窗口类
BOOL bRet = RegisterClass(&wcex); //A RegisterClass U RegisterClassW 扩展 RegisterClassExA /ExW
if (bRet == FALSE)
{
return ;
}
//3.创建窗口 并且显示跟更新窗口
HWND hWnd = CreateWindowW(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
,
CW_USEDEFAULT,
,
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, , )) != )
{
if (bRet == -)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg); //键盘消息转换为小写.
DispatchMessage(&msg); //分发消息.将我们的消息传递给我们的回调函数处理.
}
} return ;
} //
// 函数: 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();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return ;
}

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

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, //
, , , , //设置X Y 坐标.设置高度跟宽度.
hWnd, //父类句柄
(HMENU)IDC_MY_BUTTON_ONE,
g_hInst,
nullptr); CreateWindowW( //创建按钮
TEXT("BUTTON"),
TEXT("获取"),
WS_CHILD | WS_VISIBLE, //
, , , , //设置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);
}

  

win32程序之子窗口编程的更多相关文章

  1. Win32 程序开发:窗口类结构体 WNDCLASS 和 WNDCLASSEX

    一.窗口类结构体简介 窗口类结构体包含了窗口的各种参数信息.比如:窗口的图标.菜单栏.背景颜色.窗口的消息处理等等. 窗口类结构体有两个:WNDCLASS(早期版本) 和 WNDCLASSEX(新版本 ...

  2. win32程序之窗口程序,以及消息机制

    win32程序值窗口程序,以及消息机制 一丶简介 通过上一讲.我们了解了窗口其实是绘制出来的.而且是不断绘制的过程. 所以窗口的本质是绘制. 但是我们现在看到的窗口程序.都可以点击关闭按钮. 使用鼠标 ...

  3. Win32 程序开发:创建一个应用程序窗口

    一.创建一个应用程序窗口 代码如下: // 头文件 #include <windows.h> // 全局变量 WCHAR g_lpszClassName[] = L"CLASSN ...

  4. WPF中嵌入普通Win32程序的方法

    公司现在在研发基于.Net中WPF技术的产品,由于要兼容旧有产品,比如一些旧有的Win32程序.第三方的Win32程序等等,还要实现自动登录这些外部Win32程序,因此必须能够将这些程序整合到我们的系 ...

  5. win32程序通过LPCREATESTRUCT中的lpCreateParams传递参数给窗口过程函数

    win32窗口程序中如果需要给窗口过程函数传递自定义参数,可以通过LPCREATESTRUCT结构体中的lpCreateParams进行传递. 创建窗口实例函数: m_hWnd = CreateWin ...

  6. WIN32进阶必备:跟随鼠标移动的子窗口

    上两张Demo的图,方便朋友们选择是否继续看文章. 在子窗口的白色区域按下鼠标左键不放并移动鼠标可以拖拽子窗口跟随鼠标移动. 选择继续看下去的朋友不要担心,接下来就是正文了. PART 1:Demo功 ...

  7. C#在父窗口中调用子窗口的过程(无法访问已释放的对象)异常,不存在从对象类型System.Windows.Forms.DateTimePicker到已知的托管提供程序本机类型的映射。

    一:C#在父窗口中调用子窗口的过程(无法访问已释放的对象)异常 其实,这个问题与C#的垃圾回收有关.垃圾回收器管 理所有的托管对象,所有需要托管数据的.NET语言(包括 C#)都受运行库的 垃圾回收器 ...

  8. windows 编程 —— 子窗口类别化(Window Subclassing)

    对于子窗口控件,有时我们可能会想要获取子窗口的某些消息,比如在一个主窗口下有三个按钮,如果想要实现使用键盘Tab或者Shift-Tab键来使焦点切换于不同按钮之间,这时就可以使用子窗口类别化(Wind ...

  9. windows 编程 —— 子窗口 与 子窗口控件

    目录: 子窗口与主窗口的交互 子窗口控件 按钮类别 button 滚动条类别 scrollbar 静态类别  static 编辑框类别 edit 清单方块 listbox 子窗口与主窗口的交互 创建窗 ...

随机推荐

  1. 递归打印lua中的table

    在lua中,table是比较常用的数据形式,有时候为了打印出里面的内容,需要做一些特殊处理. 废话不多讲,直接粘代码: print = release_print -- 递归打印table local ...

  2. P3398 仓鼠找sugar (一道LCA的裸题)

    https://www.luogu.org/problemnew/show/P3398 题意简单概括一下就是求树上两条路径是否相交; 有这样一个性质: if相交,则必有lca(a,b) 在路径c &l ...

  3. LOJ-10097(2-sat问题)

    题目链接:传送门 思路: 2-sat问题,如果选每个集合最多有两个元素,eg:(Ai,Ai’),(Bi,Bi’): 如果Ai,Bi冲突,就只能选Ai,Bi’(建立边),然后缩点,查找有无相同集合的点在 ...

  4. ExtJS中listener方法和handler方法的区别

    listener方法和handler方法的区别在文档中的说明的太玄乎了,看不懂 listeners监听能够对一个click Event事件添加任意多个的事件响应处理函数 而handler处理只能够通过 ...

  5. UEditor可以如何直接复制word的图文内容到编辑器中?

    下载并打开工程: 文档的上传 运行: 复制随便一篇文档,粘贴进去. 通过粘贴后,文档以及图片被粘贴进来了,看看html代码:   图片全部使用img标签统一.传输进度条的效果也不错. 文档图片被放置在 ...

  6. xtrabackup单表备份与恢复

    官网最新版本下载地址 https://www.percona.com/downloads/XtraBackup/LATEST/ yum install percona-xtrabackup; [epe ...

  7. js实现图片查看器(图片的缩放、旋转、拖拽)

    一.关于图片查看器. 目前网络上能找到的图片查看器很多,谁便一搜就能出来.如:jquery.iviewer.js.Viewer.js这两个js文件,其中功能也足够满足大部分开发需求.但是单纯的就想实现 ...

  8. 学习笔记----php环境配置

    Php开发环境自定义搭建 (万事开头难) 第一步:Apache安装(httpd-2.4.37-win64-VC15.zip) 下载已编译apache安装包:Apachelounge官方下载地址:htt ...

  9. 导入Dynamic Web Project后程序有红叉但是可以运行

    解决方法: 进入工程下的.setting文件夹,用记事本编辑org.eclipse.wst.common.project.facet.core.xml, 把<runtime name=" ...

  10. Linux 常用分区方式

    1 分两个区 主目录:/ 交换分区:swap 2 常用分区方式,以使用100G空间安装linux为例 引导分区: 挂载点/boot,分区格式ext4,500M以内即可 交换分区: 无挂载点,分区格式选 ...