win32分割窗口的一个简易做法,非常好的编程思维,但是在实践中还是有问题的:需要不断的刷新父窗口,导致子窗口响应消息受到影响

使用win32写一个分割窗口为若干子窗口,随着鼠标在“分割条”上拖动,可以动态的改变子窗口的大小,从而让程序的界面可以显示不同模块的内容,这个需求是编程当中经常遇到的。
本人在写了一个CTP交易程序,就遇到登录成功以后一个页面显示今日委托、今日成交、今日持仓三大模块。于是,我在这个页面建立了三个STATIC控件子窗口,分别显示不同的内容。
话不多说,上图看:
图中,分割条是虚的,并没有真实的绘制
废话少说,上代码:

// SplitWnd.cpp : 定义应用程序的入口点。
//第一步,建立主窗口和子窗口
//在WinMain()里hwndMain = CreateWindow();
//在WindowProc()里的WM_CREATE里,分别hwndEdit / hwndPreview / hwndTitleimg = CreateWindow();
// 第二步,确定分割线的位置,建立几条可以拖动的分割线(实际上是矩形)
// 通过全局变量初始化分割线的位置和子窗口的位置
//在WM_SIZE里,MoveWindow()到预定的位置。
//之后你就会看到左侧的hwndEdit窗口,右侧上方的hwndPreview窗口,下方的hwndTitleimg窗口。
//第三步,鼠标按在子窗口空隙形成的分割线(条)的时候拖动,子窗口能任意调整彼此之间的大小。怎么做呢?简单的一种做法就是,在鼠标拖动的时候画出一条矩形阴影来模拟,
// 等鼠标释放时重新调整大小,也就是WM_SIZE里根据鼠标的位置设置3个子窗口的大小。复杂点的做法,就是分割条也当作一个子窗口CreateWindow()出来,不过有点麻烦,暂且不提。
//下面给出完整代码:#include "SplitWnd.h"//头文件里啥也没有,主要是需要#include <windows.h>#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名
POINT pt = {100,100 };//横竖分割线的交叉的,三个窗口的大小都和这个点有密切的关系,都是根据这个点的坐标来绘制的int LineWidth =50;     //分割线的厚度(宽度),为了效果我给了50像素宽的分割条,实际应用当中改为5像素宽就美观了!!!
INT WidthOfWnd = 0;//子窗口的宽度,每次使用把子窗口的宽度保存下来方便使用,能够让程序简单流畅
INT HeighthOfWnd = 0;//子窗口的高度,每次使用把子窗口的高度度保存下来方便使用,能够让程序简单流畅
bool isOnVLine = false;
bool isOnHLine = false;
HWND MainWnd = 0;       //主框架窗口句柄
HWND ChildOrder=0;      //委托单窗口句柄,保含已成交未成交的单子信息
HWND ChildTrade = 0;    //成交单窗口句柄,目前持仓信息全部统计在这里
HWND ChildNowTrade = 0; //交易持仓,目前持仓信息全部统计在这里// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
//判断鼠标落在竖线上
//参数是鼠标落点的两个坐标
bool OnVerticalRect(HWND hWnd, int x, int y);
//判断鼠标落在横线上
//参数是鼠标落点的两个坐标
bool OnHorirontleRect(HWND hWnd, int x, int y);
//废弃的函数:
//绘制分割线
void DrawSplitRect(HDC hdc, HPEN mPen, POINT mPt, BOOL IsVertOrHori);//废弃的函数:
//绘制分割线
void DrawLine(HWND hwnd);//下面需要一个函数来解决问题:改变所有需要改变的窗口
void ChangeWnd();int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int  nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此处放置代码。// 初始化全局字符串LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadStringW(hInstance, IDC_SPLITWND, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SPLITWND));MSG msg;// 主消息循环:while (GetMessage(&msg, nullptr, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam;
}//  函数: MyRegisterClass()
//  目标: 注册窗口类。
ATOM MyRegisterClass(HINSTANCE hInstance)
{WNDCLASSEXW wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style          = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc    = WndProc;wcex.cbClsExtra     = 0;wcex.cbWndExtra     = 0;wcex.hInstance      = hInstance;wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SPLITWND));wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_SPLITWND);wcex.lpszClassName  = szWindowClass;wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassExW(&wcex);
}//   函数: InitInstance(HINSTANCE, int)
//   目标: 保存实例句柄并创建主窗口
//   注释:
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{hInst = hInstance; // 将实例句柄存储在全局变量中MainWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (!MainWnd){return FALSE;}ShowWindow(MainWnd, nCmdShow);UpdateWindow(MainWnd);return TRUE;
}//  函数: 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_SIZE:{pt.x =LOWORD(lParam)/2;    //窗口的宽pt.y = HIWORD(lParam)/2 ;  //窗口的高WidthOfWnd = LOWORD(lParam);//把窗口的宽度保存下来,使用较为方便HeighthOfWnd = HIWORD(lParam);//把窗口的高度保存下来,使用较为方便ChangeWnd();// DrawLine(hWnd);}break;case WM_CREATE:{//正确://char tmpt[124];//wsprintfA(tmpt, "窗口的大小:\n宽:%d\n高:%d\n", LOWORD(lParam), HIWORD(lParam));//MessageBoxA(NULL, tmpt, "初始化窗口", MB_OK);//RECT rect = { 0 };//GetClientRect(hWnd, &rect);//pt.x = rect.right / 2;//pt.y = rect.bottom / 2;//委托单窗口ChildOrder = CreateWindowEx(0, L"STATIC", L"委托单子窗口,全部成交未成交都在这里", WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY,0, 0, pt.x-4, pt.y-4, hWnd, (HMENU)1001, hInst, NULL);//成交单窗口ChildTrade = CreateWindowEx(0, L"STATIC", L"成交单窗口,全部成交单都在这里", WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, pt.x + 4, 0, WidthOfWnd, pt.y - 4, hWnd, (HMENU)1002, hInst, NULL);;    //交易持仓,目前持仓信息全部统计在这里//持仓单窗口ChildNowTrade = CreateWindowEx(0, L"STATIC", L"持仓单窗口,全部持仓单都在这里", WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, pt.x + 4, 0, WidthOfWnd, pt.y - 4, hWnd, (HMENU)1003, hInst, NULL);;    //交易持仓,目前持仓信息全部统计在这里}break;case WM_LBUTTONDOWN:{//SetCapture函数功能:该函数在属于当前线程的指定窗口里设置鼠标捕获。//一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。//同一时刻只能有一个窗口捕获鼠标。//如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。//返回值:返回值是上次捕获鼠标的窗口句柄。如果不存在那样的句柄,返回值是NULL。//备注:只有前台窗口才能捕获鼠标。//如果一个后台窗口想捕获鼠标,则该窗口仅为其光标热点在该窗口可见部份的鼠标事件接收消息。//另外,即使前台窗口已捕获了鼠标,用户也可点击该窗口,将其调入前台。//当一个窗日不再需要所有的鼠标输入时,创建该窗口的线程应当调用函数ReleaseCapture来释放鼠标。此函数不能被用来捕获另一进程的鼠标输入。if (OnVerticalRect(hWnd, LOWORD(lParam), HIWORD(lParam))){//MessageBox(NULL, L"点击在竖线上了!", L"竖线", MB_OK);isOnVLine = true;SetCursor(LoadCursor(NULL, IDC_CROSS));//当鼠标点击到竖向分割条时光标变形为十字}if (OnHorirontleRect(hWnd, LOWORD(lParam), HIWORD(lParam))){// MessageBox(NULL, L"点击在横线上了!", L"横线", MB_OK);isOnHLine = true;SetCursor(LoadCursor(NULL, IDC_CROSS));//当鼠标点击到横向分割条时光标变形为十字}// SetCapture(hWnd);}break;case WM_LBUTTONUP://按下鼠标,拖过来:, {if (isOnVLine)//点击在竖线上了!{//MessageBox(NULL, L"点击在竖线上了!", L"竖线", MB_OK);pt.x = LOWORD(lParam);//把竖的分割线拖过来,那就只改变横坐标}if (isOnHLine)//点击在横线上了!{//MessageBox(NULL, L"点击在横线上了!", L"横线", MB_OK);pt.y = HIWORD(lParam);//把横的分割线拖过来,那就只改变纵坐标}//此函数调用已经被废弃//此函数调用已经被废弃//此函数调用已经被废弃// DrawLine(hWnd);//此函数调用已经被废弃ReleaseCapture();//下面需要一个函数来解决问题:改变所有需要改变的窗口ChangeWnd();}break;case WM_COMMAND:{// 分析菜单选择:switch (LOWORD(wParam)){case 1001:{switch (HIWORD(wParam)){case STN_DBLCLK:{MessageBox(NULL, L"1001被双击\n委托单子窗口", L"委托", MB_OK);}break;//case STN_CLICKED://{//  MessageBox(NULL, L"1001被单击", L"Infor", MB_OK);//}//break;default:break;}}break;case 1002:{switch (HIWORD(wParam)){case STN_CLICKED://MessageBox(NULL, L"1002被点击", L"Infor", MB_OK);break;case STN_DBLCLK:MessageBox(NULL, L"1002被双击点击\n今日成交记录", L"成交", MB_OK);break;default:break;}}break;case 1003:{switch (HIWORD(wParam)){case STN_CLICKED://MessageBox(NULL, L"1002被点击", L"Infor", MB_OK);break;case STN_DBLCLK:MessageBox(NULL, L"1003被双击点击\n持仓信息子窗口", L"持仓", MB_OK);break;default:break;}}break;case IDM_ABOUT:DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}}break;case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);// TextOutA(hdc, 50, 150, "我是裴英轩,裴英轩裴英轩,裴英轩", 33);//遵循出栈的规则,依次清理// ReleaseDC(hWnd, hdc);EndPaint(hWnd, &ps);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{UNREFERENCED_PARAMETER(lParam);switch (message){case WM_INITDIALOG:return (INT_PTR)TRUE;case WM_COMMAND:if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL){EndDialog(hDlg, LOWORD(wParam));return (INT_PTR)TRUE;}break;}return (INT_PTR)FALSE;
}//判断鼠标是否落在竖线分割条上
//参数是鼠标落点的两个坐标
bool OnVerticalRect(HWND hwnd, int x, int y)
{bool isok = false;if (x >= pt.x - LineWidth / 2 && x <= pt.x + LineWidth/2&&y<=pt.y + LineWidth / 2&& y >=0)//目标点与竖线相近{isok = true;// //SetCapture函数功能:该函数在属于当前线程的指定窗口里设置鼠标捕获。// //一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。// //同一时刻只能有一个窗口捕获鼠标。// //如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。// //返回值:返回值是上次捕获鼠标的窗口句柄。如果不存在那样的句柄,返回值是NULL。// //备注:只有前台窗口才能捕获鼠标。// //如果一个后台窗口想捕获鼠标,则该窗口仅为其光标热点在该窗口可见部份的鼠标事件接收消息。// //另外,即使前台窗口已捕获了鼠标,用户也可点击该窗口,将其调入前台。// //当一个窗日不再需要所有的鼠标输入时,创建该窗口的线程应当调用函数ReleaseCapture来释放鼠标。此函数不能被用来捕获另一进程的鼠标输入。SetCapture(hwnd);}return isok;
}//判断鼠标是否落在横线分割条上
//参数是鼠标落点的两个坐标
bool OnHorirontleRect(HWND hwnd, int x, int y)
{bool isok = false;if (x>0&&x< WidthOfWnd &&y >= pt.y - LineWidth / 2 && y <= pt.y + LineWidth/2)//目标点与竖线相近{isok = true;//SetCapture函数功能:该函数在属于当前线程的指定窗口里设置鼠标捕获。//一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。//同一时刻只能有一个窗口捕获鼠标。//如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。//返回值:返回值是上次捕获鼠标的窗口句柄。如果不存在那样的句柄,返回值是NULL。//备注:只有前台窗口才能捕获鼠标。//如果一个后台窗口想捕获鼠标,则该窗口仅为其光标热点在该窗口可见部份的鼠标事件接收消息。//另外,即使前台窗口已捕获了鼠标,用户也可点击该窗口,将其调入前台。//当一个窗日不再需要所有的鼠标输入时,创建该窗口的线程应当调用函数ReleaseCapture来释放鼠标。此函数不能被用来捕获另一进程的鼠标输入。SetCapture(hwnd);}return isok;
}//废弃的函数:
//绘制分割条
void DrawSplitRect(HDC hdc, HPEN mPen, POINT mPt,BOOL IsVertOrHori)
{//BOOL IsVertOrHori为真绘制横线,为假绘制垂直线SelectObject(hdc,mPen);if (IsVertOrHori)//绘制竖线分割线{//绘制竖线分割线//MoveToEx(hdc, mPt.x, 0, NULL);//横坐标一样,垂直线//LineTo(hdc, mPt.x, mPt.y);//横坐标一样,垂直线,起点纵坐标加上线的长度就是线的终点纵坐标Rectangle(hdc, mPt.x - LineWidth / 2, 0, mPt.x + LineWidth / 2, mPt.y);isOnVLine = false;//复位}else//绘制横线分割线{//绘制横线分割线,水平分割线的长度为客户区窗口的宽度//MoveToEx(hdc, 0, mPt.y, NULL);//纵坐标一样,水平线//LineTo(hdc, WidethOfWnd,mPt.y);//纵坐标一样,水平线,起点横坐标加上线的长度就是线的终点横坐标//不在绘制直线,而是根据pt点绘制横竖两个矩形Rectangle(hdc, 0,mPt.y - LineWidth / 2, WidthOfWnd,  mPt.y+ LineWidth / 2);isOnHLine = false;//复位}}
//废弃的函数:
//绘制分割线,实际上是绘制一个rectangle,
//因为直线很容易被新建立的窗口遮挡,从而影响分割窗口的逻辑
void DrawLine(HWND hwnd)
{HDC hdc = GetDC(hwnd);HPEN MyPen = CreatePen(PS_SOLID, LineWidth, RGB(180, 225, 150));SelectObject(hdc, MyPen);// SendMessageW(hwnd, WM_PAINT, 0, 0);RECT rect1 = { 0 };GetClientRect(hwnd, &rect1);InvalidateRect(hwnd, &rect1, TRUE);DrawSplitRect(hdc, MyPen, pt, 0);        //水平分割线DrawSplitRect(hdc, MyPen, pt, 1);       //垂直分割线DeleteObject(MyPen);ReleaseDC(hwnd, hdc);
}//下面需要一个函数来解决问题:改变所有需要改变的窗口
void ChangeWnd()
{MoveWindow(ChildOrder, 0, 0, pt.x - LineWidth / 2, pt.y - LineWidth / 2, TRUE);//改变委托单子窗口的大小MoveWindow(ChildTrade, pt.x + LineWidth / 2, 0, WidthOfWnd, pt.y - LineWidth / 2, TRUE);//改变成交子窗口的大小MoveWindow(ChildNowTrade, 0, pt.y + LineWidth / 2, WidthOfWnd, HeighthOfWnd, TRUE);//改变持仓子窗口的大小isOnHLine = false;//复位,等待下一次点击分割条改变窗口isOnVLine = false;//复位,等待下一次点击分割条改变窗口}

看看实际的效果:
看看实际的效果

win32分割窗口的一个简易做法,非常好的编程思维(一)相关推荐

  1. 【转】编程思维轻松培养一个有条理,思路清晰的孩子

    编程属于理科生学习的东西? 编程一定要成为码农吗? 其实编程的核心是学习一种思维方式 比尔盖茨说:学习编程可以锻炼你的思维,帮助你更好地思考,创建一种我认为在各领域都非常有用地思维方式.在美国,编程已 ...

  2. wxpython分割窗口_wxPython实现分隔窗口

    本文实例为大家分享了wxPython分隔窗口的具体代码,供大家参考,具体内容如下 1.分割窗口 分隔窗口(wx.SplitterWindow)就是将窗口分成两部分,即左右或上下两部分,如下图所示窗口, ...

  3. python写一个文件下载器_Python3使用TCP编写一个简易的文件下载器

    原标题:Python3使用TCP编写一个简易的文件下载器 利用Python3来实现TCP协议,和UDP类似.UDP应用于及时通信,而TCP协议用来传送文件.命令等操作,因为这些数据不允许丢失,否则会造 ...

  4. Win32 API 打开另一个进程

    Win32 API 打开另一个进程,这是一些黑客编程技术中的一个步骤,当然也可以用来做好事: 首先要包含Tlhelp32.h: 在OpenProcessByProcessNmae函数中通过快照枚举进程 ...

  5. 简单java socket_基于Java Socket实现一个简易在线聊天功能(一)

    最近做了一个项目,其中有一个在线网页交流的需求,好久没写代码了,手都生疏了,于是先写demo练练手,分享到脚本之家平台,以此做个记录,方便自己和大家使用. 先给大家说下实现步骤分这样几大步: 1.使用 ...

  6. 鸡啄米vc++2010系列40(文档、视图和框架:分割窗口)

    分割窗口概述 分割窗口,顾名思义,就是将一个窗口分割成多个窗格,在每个窗格中都包含有视图,或者是同一类型的视图,或者是不同类型的视图. MFC分割窗口的方式有两种,动态分割和静态分割. 动态分割窗口通 ...

  7. 【数字图像处理】 二.MFC单文档分割窗口显示图片

    本文是讲述<数字图像处理>系列文章,继上篇讲述BMP格式图片和显示后,该篇讲述如何对单文档进行分割.主要是采用CSplitterWnd静态分割窗口显示图片等相关知识.本文主要结合自己的课程 ...

  8. 如何搭建一个简易的Web框架

    Web框架本质 什么是Web框架, 如何自己搭建一个简易的Web框架?其实, 只要了解了HTTP协议, 这些问题将引刃而解. 简单的理解:  所有的Web应用本质上就是一个socket服务端, 而用户 ...

  9. java实现简易聊天窗口先运行服务器还是客户端_一个简易聊天功能的服务器端和客户端源码...

    学习完J2SE可以写一个简易的聊天软件来让刚学的知识融会贯通,代码注释的很详细哦! 开发版本历程: V0.1:客户端实现一个界面 V0.2:客户端界面有输入框和显示框的界面 V0.3:客户端关闭按钮可 ...

最新文章

  1. Java操作Kafka创建Topic、Producer、Consumer
  2. html 按钮ajax请求,使用单个提交按钮和Ajax在JSP中提交两个HTML表单
  3. php怎么弄自动填充,ThinkPHP 自动填充(自动完成)详解及实例
  4. Android5.1.1源码 - 让某个APP以解释执行模式运行
  5. define宏定义和const定义之间的区别
  6. 鸿蒙系统的全面开源,华为:打造全球的操作系统,鸿蒙今日全面开源!
  7. 三个ImageView 实现无线轮播 方法
  8. formSelects使用
  9. 毕设问题小记——No Dialect mapping for JDBC type:-1错误
  10. “基因编辑婴儿”惹争议,那你知道机器学习在脱靶效应中的作用吗?
  11. 《CCIE路由和交换认证考试指南(第5版) (第1卷)》——导读
  12. 区块链、ICO,养肥的是开发者和一群黑客
  13. linux 扫描开放的端口命令,在Linux中,如何检查开放的端口(扫描)
  14. 【机器学习实战】1、机器学习主要任务
  15. 单纯形法的代码实现与退化算例
  16. python debug配置launch.json例子
  17. 移动广告平台Android SDK接入指南
  18. 简述igp和egp_路由协议的常见分类——GGP、EGP和IGP介绍
  19. KubeEdge+Fabedge集成环境搭建教程
  20. Java网课基础笔记(4)19-07-16

热门文章

  1. 中学学生成绩管理系统
  2. windows xp 驱动开发(十八) USB驱动程序开发用到的工具总结
  3. 智能家居系统的发展趋势
  4. SSM+校园社团平台 毕业设计-附源码251554
  5. 宜搭产品生态伙伴政策——宜搭:高效的低代码应用构建平台
  6. Linux小白的大师之路
  7. PowerPoint文档“大减肥”(downmoon)
  8. C#代码实现 - 扑克牌排序
  9. Linux 下的 3D 设计软件-FreeCAD
  10. js_window.open新标签页,当前标签页打开