win32 split window of a simple approach, very good programming thinking

In win32, the split bar is used to split a parent window into several sub windows. These sub windows can be resized freely with the drag of the split bar, which can make the program more beautiful.
As shown in the following figure: the drawing window is divided into four sub windows by two horizontal and vertical dividing bars. In fact, five static windows constitute these two split bars.
When we drag the splitter bar, we actually change the relative position and size of the five static sub windows, so as to achieve the effect of dragging the splitter bar. It can be said here that what you see on the screen is not what you understand, what you see is not what you get.

Or that sentence: on the code`// Win32StaticWnd.cpp: defines the entry point for the application.
//

#include "framework.h" / / every win32 automatically generated program has this header file, and other header files you need can be written in it
#Include "Win32StaticWnd.h" / / there is nothing in it, only two lines: #pragma once #include "resource.h"

#define MAX_LOADSTRING 100

//Global variables:
HWND hMainWnd;// Main window handle
HINSTANCE hInst; // Current instance
WCHAR szTitle[MAX_LOADSTRING]; // Title Block text
WCHAR szWindowClass[MAX_LOADSTRING]; // Main window class name
HWND VSplitUp, VSplitDn, HSplitLft, HSplitRgt, CenterSplit;// Splitter window handle
BOOL IsOnVSplitUp, IsOnVSplitDn, IsOnHSplitLft, IsOnHSplitRgt, IsOnCenterSplit=FALSE;// Judge whether the click is on the split bar
INT LineWidth = 10;
INT HLongLft , HLongRgt,VLongUp, VLongDn ,MainLength,MainHeight= 0;// The length of the horizontal and vertical split bar, and the length and height of the main window
//Forward declaration of functions contained in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
//Initialization display of window
void OnSize(INT X, INT Y);
//Create split bar sub window
void CreateSplit(HWND hParent);
//After the left mouse button is lifted, move the sub window according to the relevant data
void MoveWndOnLbUp(INT PoseX, INT PoseY);

int APIENTRY wWinMain(In HINSTANCE hInstance,In_opt HINSTANCE hPrevInstance, In LPWSTR lpCmdLine,In int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: place code here.

// Initialize global string
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WIN32STATICWND, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
    return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32STATICWND));
MSG msg;

// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
return (int) msg.wParam;

}

//Function: MyRegisterClass()
//Target: register window class.
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_WIN32STATICWND));
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);    //Look at the shape of the cursor: IDC_ARROW
//wcex.hCursor = LoadCursorW(nullptr, IDC_SIZENS);   // Look at the shape of the cursor: IDC_ Sizes (up and down arrows) 

// wcex.hCursor = LoadCursorW(hInst, IDC_SIZEWE); // Look at the shape of the cursor: IDC_ Sizewe (left and right arrows)
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32STATICWND);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassExW(&wcex);

}

//
//Function: InitInstance (hint, int)
//
//Target: save the instance handle and create the main window
//
//Note:
//
//In this function, we save the instance handle in the global variable and
//Create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store the instance handle in a global variable
hMainWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hMainWnd)
{
return FALSE;
}
ShowWindow(hMainWnd, nCmdShow);
UpdateWindow(hMainWnd);
return TRUE;
}

//Function: WndProc(HWND, UINT, WPARAM, LPARAM)
//Objective: to process messages from the main window.
// WM_COMMAND - process application menu
// WM_PAINT - draw main window
// WM_DESTROY - send exit message and return
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//Create split bar sub window
CreateSplit(hWnd);
}
break;
case WM_SIZE:
{
//Initialization display of window
OnSize(LOWORD(lParam),HIWORD(lParam));
}
break;
case WM_MOUSEMOVE:
{
// BOOL IsOnVSplitUp, IsOnVSplitDn, IsOnHSplitLft, IsOnHSplitRgt, IsOnCenterSplit = FALSE;// Judge whether the click is on the split bar
//if (IsOnHSplitLft)
//{
/// / MessageBoxA(NULL, "mouse moving", "mouse moving", MB_OK);
//}

    }
    break;
    case WM_LBUTTONDOWN:
    {
        MessageBox(NULL, L"The main window receives the message of pressing the left mouse button", L"Main window: WM_LBUTTONDOWN", MB_OK);
    }
    break;
    case WM_LBUTTONUP:
    {
        //MessageBox(NULL, L "the main window receives the message of lifting the left mouse button", L "lifting: WM_LBUTTONUP", MB_OK);
        // 
        //After the left mouse button is lifted, move the sub window according to the relevant data
        MoveWndOnLbUp(LOWORD(lParam),HIWORD(lParam));

        ReleaseCapture();
        IsOnVSplitUp = IsOnVSplitDn = IsOnHSplitLft = IsOnHSplitRgt = IsOnCenterSplit = FALSE;
    }
    break;
    case WM_COMMAND:
    {

        int wmId = LOWORD(wParam);
        // Analysis menu selection:
        switch (wmId)
        {
            case 1001://Horizontal split bar left
            {
                switch (HIWORD(wParam))
                {
                    //case STN_DBLCLK:
                    //{
                    //    //MessageBox(NULL, L"1001 is double clicked \ n delegate list sub window", L "delegate", MB_OK);
                    //}
                    // break;
                    case STN_CLICKED:
                    {
           	           //MessageBox(NULL, L"1001 is clicked, horizontal split bar left", L "horizontal split bar left", MB_OK);
                        //LoadCursorW(hInst, IDC_SIZEWE);
                        SetCursor(LoadCursorW(NULL, IDC_SIZENS));//Up and down arrows
                        IsOnHSplitLft = TRUE;
                        // 
                        //SetCapture function function: this function sets mouse capture in the specified window belonging to the current thread.
                        //Once the window captures the mouse, all mouse input is for the window, whether or not the cursor is within the boundary of the window.
                        //Only one window can capture the mouse at a time.
                        //If the mouse cursor is on a window created by another thread, the system will point the mouse input to the specified window only when the mouse button is pressed.
                        //Return value: the return value is the window handle that captured the mouse last time. If there is no such handle, the return value is NULL.
                        //Note: only the foreground window can capture the mouse.
                        //If a background window wants to capture the mouse, the window only receives messages for mouse events where the cursor hotspot is visible in the window.
                        //In addition, even if the foreground window has captured the mouse, the user can click the window to transfer it to the foreground.
                        //When a window no longer needs all mouse input, the thread creating the window should call the function ReleaseCapture to release the mouse. This function cannot be used to capture mouse input from another process.
                        SetCapture(hWnd);
                    }
                    break;
                    default:
                        break;
                }
            }
            break;
            case 1002://Horizontal split bar right
            {
                switch (HIWORD(wParam))
                {
                case STN_CLICKED://Horizontal split bar right
                {
                   //MessageBox(NULL, L"1002 is clicked, horizontal split bar right", L "horizontal split bar right", MB_OK);
                    SetCursor(LoadCursorW(NULL, IDC_SIZENS));//Up and down arrows
                    IsOnHSplitRgt = TRUE;//Horizontal split bar right

                    //SetCapture function function: this function sets mouse capture in the specified window belonging to the current thread.
                    //Once the window captures the mouse, all mouse input is for the window, whether or not the cursor is within the boundary of the window.
                    //Only one window can capture the mouse at a time.
                    //If the mouse cursor is on a window created by another thread, the system will point the mouse input to the specified window only when the mouse button is pressed.
                    //Return value: the return value is the window handle that captured the mouse last time. If there is no such handle, the return value is NULL.
                    //Note: only the foreground window can capture the mouse.
                    //If a background window wants to capture the mouse, the window only receives messages for mouse events where the cursor hotspot is visible in the window.
                    //In addition, even if the foreground window has captured the mouse, the user can click the window to transfer it to the foreground.
                    //When a window no longer needs all mouse input, the thread creating the window should call the function ReleaseCapture to release the mouse. This function cannot be used to capture mouse input from another process.
                    SetCapture(hWnd);
                }
                 break;
                /*case STN_DBLCLK:
                MessageBox(NULL, L"1002 Double click and click \ n today's transaction record ", L" transaction ", MB_OK);
                break;*/
                default:
                    break;
                }
            }
            break;
            case 1003://Vertical split bar
            {
                switch (HIWORD(wParam))
                {
                    case STN_CLICKED:
                    {
                        //MessageBox(NULL, L "/ / on vertical divider", L "/ / on vertical divider", MB_OK);
                        SetCursor(LoadCursorW(NULL, IDC_SIZEWE));//Left and right arrows
                        IsOnVSplitUp = TRUE;//Vertical split bar

                        //SetCapture function function: this function sets mouse capture in the specified window belonging to the current thread.
                        //Once the window captures the mouse, all mouse input is for the window, whether or not the cursor is within the boundary of the window.
                        //Only one window can capture the mouse at a time.
                        //If the mouse cursor is on a window created by another thread, the system will point the mouse input to the specified window only when the mouse button is pressed.
                        //Return value: the return value is the window handle that captured the mouse last time. If there is no such handle, the return value is NULL.
                        //Note: only the foreground window can capture the mouse.
                        //If a background window wants to capture the mouse, the window only receives messages for mouse events where the cursor hotspot is visible in the window.
                        //In addition, even if the foreground window has captured the mouse, the user can click the window to transfer it to the foreground.
                        //When a window no longer needs all mouse input, the thread creating the window should call the function ReleaseCapture to release the mouse. This function cannot be used to capture mouse input from another process.
                        SetCapture(hWnd);

                    }
                     break;
                    //case STN_DBLCLK:
                    //    //MessageBox(NULL, L"1003 is double clicked, click \ n position information sub window", L "position", MB_OK);
                    //    break;
                    default:
                        break;
                }
            }
            break;
            case 1004://Under vertical split bar
            {
                switch (HIWORD(wParam))
                {
                    case STN_CLICKED:
                    {  
                       //MessageBox(NULL, L"1 / / under the vertical split bar", L "/ / under the vertical split bar", MB_OK); 
                        SetCursor(LoadCursorW(NULL, IDC_SIZEWE));//Left and right arrows
                        IsOnVSplitDn = TRUE;//Under vertical split bar

                        //SetCapture function function: this function sets mouse capture in the specified window belonging to the current thread.
                        //Once the window captures the mouse, all mouse input is for the window, whether or not the cursor is within the boundary of the window.
                        //Only one window can capture the mouse at a time.
                        //If the mouse cursor is on a window created by another thread, the system will point the mouse input to the specified window only when the mouse button is pressed.
                        //Return value: the return value is the window handle that captured the mouse last time. If there is no such handle, the return value is NULL.
                        //Note: only the foreground window can capture the mouse.
                        //If a background window wants to capture the mouse, the window only receives messages for mouse events where the cursor hotspot is visible in the window.
                        //In addition, even if the foreground window has captured the mouse, the user can click the window to transfer it to the foreground.
                        //When a window no longer needs all mouse input, the thread creating the window should call the function ReleaseCapture to release the mouse. This function cannot be used to capture mouse input from another process.
                        SetCapture(hWnd);
                    }
                        break;
                    //case STN_DBLCLK:
                    //    MessageBox(NULL, L"1004 is double clicked, click \ n position information sub window", L "position", MB_OK);
                    //    break;
                    default:
                        break;
                }
            }
            break;
            case 1005:
            {
                switch (HIWORD(wParam))
                {
                    case STN_CLICKED:
                    {
                        //MessageBox(NULL, L"1005 clicked", L"Infor", MB_OK);
                        SetCursor(LoadCursorW(NULL, IDC_SIZEALL));//Left and right arrows
                        IsOnCenterSplit = TRUE;

                        //SetCapture function function: this function sets mouse capture in the specified window belonging to the current thread.
                        //Once the window captures the mouse, all mouse input is for the window, whether or not the cursor is within the boundary of the window.
                        //Only one window can capture the mouse at a time.
                        //If the mouse cursor is on a window created by another thread, the system will point the mouse input to the specified window only when the mouse button is pressed.
                        //Return value: the return value is the window handle that captured the mouse last time. If there is no such handle, the return value is NULL.
                        //Note: only the foreground window can capture the mouse.
                        //If a background window wants to capture the mouse, the window only receives messages for mouse events where the cursor hotspot is visible in the window.
                        //In addition, even if the foreground window has captured the mouse, the user can click the window to transfer it to the foreground.
                        //When a window no longer needs all mouse input, the thread creating the window should call the function ReleaseCapture to release the mouse. This function cannot be used to capture mouse input from another process.
                        SetCapture(hWnd);
                    }
                        break;
                    //case STN_DBLCLK:
                    //    MessageBox(NULL, L"1005 is double clicked, click \ n position information sub window", L "position", 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);
        // TODO: add any drawing code using hdc here
        EndPaint(hWnd, &ps);
    }
        break;
    case WM_DESTROY:
    {
        PostQuitMessage(0);
    }
    break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;

}

//Message handler for the about box.
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;

}

//Initialization display of window
void OnSize(INT X,INT Y)
{
//Here you must save the width and height of the main window
MainLength=X;
MainHeight=Y;
HLongLft = HLongRgt=(X - LineWidth) / 2;// Length of horizontal dividing bar
VLongUp = VLongDn=(Y - LineWidth) / 2;// Length of vertical divider
MoveWindow(HSplitLft, 0, VLongUp, HLongLft, LineWidth, TRUE);
MoveWindow(HSplitRgt, HLongLft + LineWidth, VLongUp, HLongRgt, LineWidth, TRUE);
MoveWindow(VSplitUp, HLongLft, 0, LineWidth, VLongUp, TRUE);
MoveWindow(VSplitDn, HLongLft, VLongUp + LineWidth, LineWidth, VLongUp, TRUE);
MoveWindow(CenterSplit, HLongLft, VLongUp, LineWidth, LineWidth, TRUE);

}
//Create split bar sub window
void CreateSplit(HWND hParent)
{
//WS_EX_DLGMODALFRAME style is the most suitable for split bars,
//WS_EX_DLGMODALFRAME style is the most suitable for split bars,
//WS_EX_DLGMODALFRAME style is the most suitable for split bars,
//WS_EX_DLGMODALFRAME style is the most suitable for split bars,
//WS_EX_DLGMODALFRAME style is the most suitable for split bars,
//WS_EX_DLGMODALFRAME style is the most suitable for split bars,
//Horizontal split bar window / / the extended style is 3D WS_EX_CLIENTEDGE,WS_EX_DLGMODALFRAME style is the most suitable for split bars. It will not be displayed temporarily because the height and width are 0
HSplitLft = CreateWindowExW(WS_EX_DLGMODALFRAME, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, 0, 0, 0, 0, hParent, (HMENU)1001, hInst, NULL);
HSplitRgt = CreateWindowExW(WS_EX_DLGMODALFRAME, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, 0, 0, 0, 0, hParent, (HMENU)1002, hInst, NULL);
//Vertical bar splitter window / / the extended style is 3D style WS_EX_CLIENTEDGE,WS_EX_DLGMODALFRAME style is the most suitable for split bars. It will not be displayed temporarily because the height and width are 0
VSplitUp = CreateWindowExW(WS_EX_DLGMODALFRAME, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, 0, 0, 0, 0, hParent, (HMENU)1003, hInst, NULL);; // Trading position, the current position information is all counted here
VSplitDn = CreateWindowExW(WS_EX_DLGMODALFRAME, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, 0, 0, 0, 0, hParent, (HMENU)1004, hInst, NULL);; // Trading position, the current position information is all counted here
CenterSplit = CreateWindowExW(WS_EX_DLGMODALFRAME, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, 0, 0, 0, 0, hParent, (HMENU)1005, hInst, NULL);; // Trading position, the current position information is all counted here

}
//After the left mouse button is lifted, move the sub window according to the relevant data
void MoveWndOnLbUp(INT PosX, INT PosY)
{
If (isonvplitup) / / click the vertical split bar to move the horizontal left, horizontal right, middle and vertical sub windows
{
HLongLft = PosX;// Length of left side of horizontal dividing bar
HLongRgt =MainLength- HLongLft-LineWidth;// Length of the right side of the horizontal divider bar
MoveWindow(HSplitLft, 0, VLongUp, HLongLft, LineWidth, TRUE);// Horizontal left
MoveWindow(HSplitRgt, HLongLft + LineWidth, VLongUp, HLongRgt, LineWidth, TRUE);// Horizontal right
MoveWindow(CenterSplit, HLongLft, VLongUp, LineWidth, LineWidth, TRUE);// middle
MoveWindow(VSplitUp, HLongLft, 0, LineWidth, VLongUp, TRUE);// Vertical up
}
Else if (isonvplitdn) / / click the vertical lower split bar to move the horizontal left, horizontal right, middle and vertical lower four sub windows
{
HLongLft = PosX;// Length of left side of horizontal dividing bar
HLongRgt = MainLength - HLongLft - LineWidth;// Length of the right side of the horizontal divider bar
VLongDn = MainHeight - VLongUp - LineWidth;
MoveWindow(HSplitLft, 0, VLongUp, HLongLft, LineWidth, TRUE);// Horizontal left
MoveWindow(HSplitRgt, HLongLft + LineWidth, VLongUp, HLongRgt, LineWidth, TRUE);// Horizontal right
MoveWindow(CenterSplit, HLongLft, VLongUp, LineWidth, LineWidth, TRUE);// middle
MoveWindow(VSplitDn, HLongLft, VLongUp + LineWidth, LineWidth, VLongDn, TRUE);// Vertical down
}
Else if (isonhplitlft) / / click the horizontal left split bar to move the horizontal left, middle, vertical bottom and vertical top four sub windows
{
//HLongLft = PoseX;// Length of left side of horizontal dividing bar
//HLongRgt = MainLength - HLongLft - LineWidth;// Length of the right side of the horizontal divider bar
VLongUp = PosY;
VLongDn = MainHeight - VLongUp - LineWidth;
MoveWindow(HSplitLft, 0, VLongUp, HLongLft, LineWidth, TRUE);// Transverse left
MoveWindow(VSplitUp, HLongLft, 0, LineWidth, VLongUp, TRUE);// Vertical up
MoveWindow(VSplitDn, HLongLft, VLongUp +LineWidth, LineWidth, VLongDn, TRUE);// Vertical down
MoveWindow(CenterSplit, HLongLft, VLongUp, LineWidth, LineWidth, TRUE);// middle
}
Else if (isonhplitrgt) / / click the horizontal right split bar to change the four sub windows: horizontal right, middle, vertical bottom and vertical top
{
VLongUp = PosY;// Length on vertical divider bar
// INT , HLongRgt, VLongDn, MainLength, = 0;// The length of the horizontal and vertical split bar, and the length and height of the main window
VLongDn = MainHeight- VLongUp- LineWidth;// Length under vertical dividing bar
HLongRgt = MainLength - HLongLft - LineWidth;// Length of the right side of the horizontal divider bar
MoveWindow(HSplitRgt, HLongLft+ LineWidth, VLongUp, HLongRgt, LineWidth, TRUE);// Transverse right
MoveWindow(CenterSplit, HLongLft, VLongUp, LineWidth, LineWidth, TRUE);// middle
MoveWindow(VSplitUp, HLongLft ,0, LineWidth, VLongUp, TRUE);// Vertical up
MoveWindow(VSplitDn, HLongLft, VLongUp + LineWidth, LineWidth, VLongDn, TRUE);// Vertical down
}
else if (IsOnCenterSplit) / / click the split bar in the middle to change all five sub windows
{
//INT HLongLft, VLongUp, MainLength, = 0;// The length of the horizontal and vertical split bar, and the length and height of the main window

    HLongLft = PosX;    //Length of horizontal dividing bar
    HLongRgt = MainLength - HLongLft - LineWidth;
    VLongUp = PosY;     //Length of vertical divider
    VLongDn = MainHeight - VLongUp - LineWidth;

    MoveWindow(HSplitLft, 0, VLongUp, HLongLft, LineWidth, TRUE);//Horizontal left
    MoveWindow(HSplitRgt, HLongLft + LineWidth, VLongUp, HLongRgt,LineWidth,  TRUE);//Horizontal right
    MoveWindow(VSplitUp, HLongLft, 0, LineWidth, VLongUp, TRUE);//Vertical up
    MoveWindow(VSplitDn, HLongLft, VLongUp + LineWidth, LineWidth, VLongDn, TRUE);//Vertical down
    MoveWindow(CenterSplit, HLongLft, VLongUp, LineWidth, LineWidth, TRUE);//middle

}

}
`

After compiling and running, the effect is as follows:
It can also be as follows:

Keywords: C++ WIN32

Added by Jon12345 on Sat, 15 Jan 2022 10:12:43 +0200