Click here to Skip to main content
15,881,746 members
Articles / Programming Languages / C++
Article

Win32 splitter window project

Rate me:
Please Sign up or sign in to vote.
3.43/5 (20 votes)
26 Jul 20072 min read 72.5K   5.4K   37   13
Creating a simple, pure WIN32 SDI application with a split main window

Introduction

Screenshot - image001.gif

In this article, I am going to walk you through creating a simple pure WIN32 SDI application with a split main window. The window will be split into a left pane, right pane and main window to act as a splitter bar. It has button at the bottom to change the color of the window dynamically. It also uses the XP theme for the controls used in the application, which is enabled through a manifest file.

Most controls in this window were created using the Win32 APIs except a dialog box, which was created with the resource editor used to change the color of the window dynamically. Let's start creating the project. First of all, start Visual Studio and create a new project. Select Win32Project, give your project a name and click OK.

Screenshot - image002.gif

Screenshot - image003.gif

Click Next...

Screenshot - image004.gif

Select "Windows application" and click the Finish button.

Usage

Code used to create a splitter window

The way to create a splitter window is by creating three windows:

  • The main window
  • The left window
  • The right window

Make the left and the right window as child windows to the main window. Use the WS_EX_CLIENTEDGE extended window style while creating the window with the API CreateWindowEx, as shown below:

C++
// In WM_CREATE of the main window procedure 
case WM_CREATE : GetClientRect(hWnd, &rect);

// Creates the left window using the width and height read from the XML 
// files
g_hleftwnd = CreateWindowEx(WS_EX_CLIENTEDGE, LEFT_WINDOW_CLASS, "", 
    WS_CHILD | WS_VISIBLE, rect.left, rect.top + TOP_POS, LEFT_WND_WIDTH, 
    (rect.bottom - rect.top) – (TOP_POS + BOTTOM_POS), hWnd, NULL, 
    hInst, NULL);
if(NULL != g_hleftwnd)
{
    ShowWindow(g_hleftwnd, SW_SHOW);
    UpdateWindow(g_hleftwnd);
}

// Creates the right window using the width and height read from the XML
// files
g_hrightwnd = CreateWindowEx(WS_EX_CLIENTEDGE, RIGHT_WINDOW_CLASS, "", 
    WS_CHILD | WS_VISIBLE | SS_SUNKEN, 
    rect.left + LEFT_WINDOW_WIDTH + SPLITTER_BAR_WIDTH,
    rect.top + TOP_POS, 
    rect.right - (rect.left + LEFT_WINDOW_WIDTH +SPLITTER_BAR_WIDTH),
    (rect.bottom - rect.top) - (TOP_POS + BOTTOM_POS),
    hWnd, NULL, hInst, NULL);

if(NULL != g_hrightwnd)
{
    ShowWindow(g_hrightwnd, SW_SHOW);
    UpdateWindow(g_hrightwnd);
}

Adjust the width of the right and left windows so that the main window will act as a splitter bar. We can adjust the width of the splitter bar through MACRO SPLITTER_BAR_WIDTH, which is defined in the file macro.h. Handle the window messages...

  • WM_LBUTTONDOWN
  • WM_MOVE
  • WM_LBUTTONUP
  • WM_SIZE

...as shown in the code below:

C++
// Case statement to handle the left mouse button down message
// received while the mouse left button is down
case WM_LBUTTONDOWN :
{
    int xPos;
    int yPos;

    // Varible used to get the mouse cursor x and y co-ordinates
    xPos = (int)LOWORD(lParam);
    yPos = (int)HIWORD(lParam);

    // Checks whether the mouse is over the splitter window
    xSizing = (xPos > nleftWnd_width - SPLITTER_BAR_WIDTH &&
    xPos < nleftWnd_width + SPLITTER_BAR_WIDTH );

    // If the mouse is over the splitter then set mouse cursor 
    // image to IDC_SIZEWE which helps the user to drag the window
    if(xSizing)
    {
        // Api to capture mouse input
        SetCapture(hWnd);
        if(xSizing)
        {
            SetCursor(hcSizeEW);
        }
    }
}
break;


case WM_MOUSEMOVE :
{
    int xPos;
    int yPos;

    // Get the x and y co-ordinates of the mouse
    xPos = (int)LOWORD(lParam);
    yPos = (int)HIWORD(lParam);

    // Checks if the left button is pressed during dragging the splitter
    if(wParam == MK_LBUTTON)
    {
        // If the window is dragged using the splitter, get the
        // cursors current postion and draws a focus rectangle

        if(xSizing)
        {
            RECT focusrect;
            HDC hdc;

            hdc = GetDC(hWnd);
            GetClientRect(hWnd, &rect);

            if(xSizing)
            {
                SetRect(&focusrect, nleftWnd_width - (WIDTH_ADJUST * 2),
                    rect.top + TOP_POS, nleftWnd_width + WIDTH_ADJUST,
                    rect.bottom - BOTTOM_POS);

                // Draw a rectangle while the window is dragged uisng 
                // the splitter bar
                DrawFocusRect(hdc, &focusrect);

                // Get the size of the left window to increase
                nleftWnd_width = xPos;

                // Draws a focus rectangle
                SetRect(&focusrect, nleftWnd_width - (SPLITTER_BAR_WIDTH * 2),
                    rect.top + TOP_POS, nleftWnd_width + SPLITTER_BAR_WIDTH,
                    rect.bottom - BOTTOM_POS);
                DrawFocusRect(hdc, &focusrect);
            }
            ReleaseDC(hWnd, hdc);
        }
    }

    // Set the cursor image to east west direction when the mouse is over 
    // the splitter window
    if( (xPos > (nleftWnd_width - SPLITTER_BAR_WIDTH) &&
        xPos < (nleftWnd_width + SPLITTER_BAR_WIDHT))
    {
        SetCursor(hcSizeEW); 
    }
}
break;


case WM_LBUTTONUP :
if(xSizing)
{
    RECT focusrect;
    HDC hdc;

    // Releases the captured mouse input
    ReleaseCapture();

    // Get the main window dc to draw a focus rectangle
    hdc = GetDC(hWnd);

    GetClientRect(hWnd, &rect);
    if(xSizing)
    {
        SetRect(&focusrect, nleftWnd_width - (WIDTH_ADJUST * 2), 
            rect.top + TOP_POS, nleftWnd_width + WIDTH_ADJUST, 
            rect.bottom - 80);

        // Call api to vanish the dragging rectangle
        DrawFocusRect(hdc, &focusrect);
        xSizing = FALSE;
    }
    // Release the dc once done 
    ReleaseDC(hWnd, hdc);
}
// Post a WM_SIZE message to redraw the windows
PostMessage(hWnd, WM_SIZE, 0, 0);
break;

We will get this message whenever the user tries to resize the window using the splitter bar. Here we will get the postion of the splitter bar and move the left and right windows accordingly, using the API MoveWindow().

C++
case WM_SIZE:

GetClientRect(hWnd, &rect);

// Call Api to move and adjust the left window postion and its
// height and width

MoveWindow(g_hleftwnd, rect.left,
    rect.top + TOP_POS, rect.left + (nleftWnd_width - WIDTH_ADJUST),
    (rect.bottom - (TOP_POS + BOTTOM_POS)), FALSE);

// Call Api to move and adjust the right window postion and its
// height and width
MoveWindow(g_hrightwnd, rect.left + nleftWnd_width + WIDTH_ADJUST,
    rect.top + TOP_POS, rect.right - (nleftWnd_width + WIDTH_ADJUST),
    rect.bottom - (TOP_POS + BOTTOM_POS), FALSE); 

MoveWindow(hclose_button, rect.right - SPACE_BUTTON_RIGHT,
    rect.bottom - SPACE_BUTTON_BOTTOM, CLOSE_BUTTON_WIDTH, 
    BUTTON_HEIGHT, FALSE);

MoveWindow(hcolor_button, 
    rect.right - (SPACE_BUTTON_RIGHT + COLOR_BUTTON_WIDTH + BUTTON_ADJUST), 
    rect.bottom - SPACE_BUTTON_BOTTOM, COLOR_BUTTON_WIDTH, 
    BUTTON_HEIGHT, FALSE);

MoveWindow(hText, rect.left, rect.top, 
    rect.right, STATIC_TEXT_HEIGHT, FALSE);

InvalidateRect(hWnd, &rect, TRUE);

break;

Code to handle the keyboard events when a tab or enter key is pressed

C++
case WM_KEYDOWN :

switch(wParam)
{
    case VK_TAB :
    if (focus == hcolor_button)
    { 
        SendMessage(focus, WM_KILLFOCUS, 0, 0);
        SendMessage(hclose_button, WM_SETFOCUS, 0, 0);
        focus = hclose_button;
    }
    else if (focus == hclose_button)
    {
        SendMessage(focus, WM_KILLFOCUS, 0, 0);
        SendMessage(hcolor_button, WM_SETFOCUS, 0, 0);
        focus = hcolor_button;
    }
    break;

    case VK_RETURN:

    if (IsWindowEnabled(focus))
    {
        SendMessage(hWnd, WM_COMMAND, 0, (LPARAM)focus);
    }
    break; 
}
break;

Code to used to color the window with the user selected RGB values

C++
case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

// Get the main window rectangle values
GetClientRect(hWnd, &rect);

// Create the brush with the RGB values selected by the user 
hmain_Wnd_brush = CreateSolidBrush(RGB(main_Wnd_clr[0],
    main_Wnd_clr[1], main_Wnd_clr[2]));

// Fill the window with the created brush
FillRect(hdc, &rect, hmain_Wnd_brush);

DeleteObject(hmain_Wnd_brush);

EndPaint(hWnd, &ps);

break;

The same code will be used in the window procedures of the left and right windows to paint them with the user-selected RGB values.

Points of interest

Most Win32 applications will not use Windows themes until explicitly asked to use them. This can be done by using the manifest file given below

XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0" 
        processorArchitecture="x86" name="App" 
        type="win32">
    </assemblyIdentity>
    <description>Splitter App</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" 
                version="8.0.50608.0" processorArchitecture="*" 
                publicKeyToken="1fc8b3b9a1e18e3b">
            </assemblyIdentity>
        </dependentAssembly>
    </dependency>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" 
                name="Microsoft.Windows.Common-Controls" 
                version="6.0.0.0" processorArchitecture="*" 
                publicKeyToken="6595b64144ccf1df" language="*">
            </assemblyIdentity>
        </dependentAssembly>
    </dependency>
</assembly>

Follow these steps: Copy this file into a text file, naming it as "Your Application Name(XXXX).exe.manifest" and add this file to the project in the resource folder as shown below.

Screenshot - image005.gif

Screenshot - image006.gif

This manifest file will help in using the themes to the control used in the windows.

Conclusion

This our first submission to The Code Project, so people who find any bugs and/or have suggestions are always welcome.

History

  • 26 July, 2007 -- Original version posted

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
Hi all, i am satheesh

i have worked in Writing windows device driver, win32 , MFC, COM and started working in WTL now.




Comments and Discussions

 
QuestionThank you.Very useful for me Pin
addicted_to_cpp15-Mar-22 10:16
addicted_to_cpp15-Mar-22 10:16 
QuestionThe link to the attached source code and project is broken. Pin
Gbenbam5-Feb-14 4:59
Gbenbam5-Feb-14 4:59 
QuestionSuggestion on modification to producep three split windows Pin
Gbenbam5-Feb-14 4:50
Gbenbam5-Feb-14 4:50 
QuestionI need help understanding this code Pin
Gbenbam5-Feb-14 4:44
Gbenbam5-Feb-14 4:44 
GeneralMy vote of 5 Pin
Jaxon730-May-12 7:44
Jaxon730-May-12 7:44 
QuestionWill not compile using VS 2010 - please help Pin
Michael B Pliam21-Apr-12 10:31
Michael B Pliam21-Apr-12 10:31 
AnswerRe: Will not compile using VS 2010 - please help Pin
steve5330-Apr-12 23:15
professionalsteve5330-Apr-12 23:15 
AnswerRe: Will not compile using VS 2010 - please help Pin
leutenent29-May-13 5:56
professionalleutenent29-May-13 5:56 
GeneralVery Informative Pin
gayatri.neelema21-Aug-08 16:28
gayatri.neelema21-Aug-08 16:28 
GeneralRe: Very Informative Pin
gayatri.neelema21-Aug-08 16:37
gayatri.neelema21-Aug-08 16:37 
QuestionPlease help Pin
yosmany4-May-08 6:21
yosmany4-May-08 6:21 
GeneralExcellent Pin
DYSEQTA12-Oct-07 17:46
professionalDYSEQTA12-Oct-07 17:46 
GeneralRe: Excellent Pin
k. satheesh_1716-Oct-07 23:44
k. satheesh_1716-Oct-07 23:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.