Layout in Win32 GUI program

Go To StackoverFlow.com

11

I have a sort of abstract question about using straight Win32 for GUI programming. As my only previous GUI experience has been in Java using Swing I'm used to having a layout manager that automatically resizes/repositions buttons and stuff when a window is resized. Is there something similar that comes built in to the Win32 API, or does one have to manually recalculate sizes and positions using absolute locations on every repaint? I assume that this is in fact the way to do it because I haven't stumbled across anything that looks like layout management in the MSDN docs, but as those are (to my mind) a tad labyrinthine I may have missed it.

Thanks for your help!

2012-04-04 02:52
by Nathan McCrina
I have some code for MFC that might be adapted to pure Win32 API calls: http://stackoverflow.com/a/5739620/598 - Mark Ransom 2012-04-04 03:43


5

You need to take a look at ATL (shipped with Visual C++), and correspondingly, WTL (not shipped, need to download).

They compile almost completely to "straight Win32", while providing a nice C++ wrapper around them. They are very lightweight (almost no weight, actually -- it's direct Win32 for 99% of the calls), and yet WTL is designed to mimic MFC's features, so it's still pretty featureful.

You need to be semi-good with C++, though.

The easiest way is to use CDialogResize<CYourDialog> in something like

// Put ATL includes before here..
#include <atlcrack.h>  // Include this from WTL for message map
#include <atlframe.h>  // Include this from WTL for CDialogResize

class CYourDialog : CDialogImpl<CYourDialog>, CDialogResize<CYourDialog>
{
    BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
    {
        this->DlgResize_Init();                     // Initialize the positions
    }

    BEGIN_MSG_MAP_EX(CYourDialog)  // Learn about message maps if you haven't
        MSG_WM_INITDIALOG(OnInitDialog)
        CHAIN_MSG_MAP(CDialogResize<CYourDialog>)   // Chain to the parent
    END_MSG_MAP()

    BEGIN_DLGRESIZE_MAP(CYourDialog)
        DLGRESIZE_CONTROL(IDOK, DLSZ_MOVE_Y)        // Layout for "OK" button
    END_DLGRESIZE_MAP()
};

DLGRESIZE_CONTROL() is the heart of the layout -- DLSZ_MOVE_Y, for example, says that you want to move IDOK vertically. You can also group them, but it gets tricky (sometimes I don't understand what's going on either)... but once you get it right, it's actually not that bad. :)


Here's a self-contained example:

#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#include <atlbase.h>
extern CComModule _Module;
#include <atlapp.h>
#include <atlcrack.h>
#include <atlwin.h>
#include <atlframe.h>
#include "resource.h"

class CMyDialog : public CDialogImpl<CMyDialog>, CDialogResize<CMyDialog>
{
public:
    enum { IDD = IDD_DIALOG1 };

private:
    BOOL OnInitDialog(CWindow wndFocus, LPARAM)
    {
        this->DlgResize_Init();
        return TRUE;
    }

    void OnOK(UINT, int, HWND) { this->EndDialog(ERROR_SUCCESS); }
    void OnCancel(UINT, int, HWND) { this->EndDialog(ERROR_CANCELLED); }

    BEGIN_MSG_MAP_EX(CMyDialog)
        MSG_WM_INITDIALOG(OnInitDialog)
        COMMAND_HANDLER_EX(IDOK, BN_CLICKED, OnOK)
        COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnCancel)
        CHAIN_MSG_MAP(CDialogResize<CMyDialog>)
    END_MSG_MAP()

    BEGIN_DLGRESIZE_MAP(CMyDialog)
        DLGRESIZE_CONTROL(IDOK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
        DLGRESIZE_CONTROL(IDCANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
    END_DLGRESIZE_MAP()
};

CComModule _Module;

int WINAPI _tWinMain(
    HINSTANCE hInstance, HINSTANCE hInstPrevious,
    LPTSTR lpCmdLine, int nCmdShow)
{
    _Module.Init(NULL, hInstance);
    {
        CMyDialog dialog;
        dialog.DoModal();
    }
    _Module.Term();
}

To compile it, you also need a file named resource.h with the following contents in the same project folder:

#define IDD_DIALOG1                     101
#define IDR_RT_MANIFEST1                103

And a file named Sample.rc added to the project, which can be edited with Visual Studio and which contains the dialog layout:

#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
#include "afxres.h"
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif
#ifdef APSTUDIO_INVOKED
1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END
#endif
IDD_DIALOG1 DIALOGEX 0, 0, 316, 180
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,205,159,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,259,159,50,14
END
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_DIALOG1, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 309
        TOPMARGIN, 7
        BOTTOMMARGIN, 173
    END
END
#endif
#endif
#ifndef APSTUDIO_INVOKED
#endif
2012-04-04 03:13
by Mehrdad
@NathanMcCrina: ATL is literally just a C++ interface/wrapper for Win32 -- if you're using C++, you'd just be giving yourself a hard time if you use the C-style APIs -- it adds nothing and makes you follow bad practices (e.g. lots of global variables, which are a bad idea, but an easy mistake). As for DirectX: I'm pretty sure they would fit together well -- it's no different from Win32, after all, since it's the same thing. Would a complete example for ATL help (probably no DirectX, just how to show a dialog)? I can make a dialog and show you how, it's really not that hard - Mehrdad 2012-04-04 03:27
Sure, I won't say no to examples - Nathan McCrina 2012-04-04 03:33
@NathanMcCrina: See update - Mehrdad 2012-04-04 04:01
Thanks so much! I'm checking it out now - Nathan McCrina 2012-04-04 04:12
I only have the Express edition, so apparently the only way to compile a project that uses ATL is to install the Windows Driver Kit; slight delay : - Nathan McCrina 2012-04-04 04:28
@NathanMcCrina: Ah yeah, sorry... hope it's not too painful haha - Mehrdad 2012-04-04 04:36
@NathanMcCrina: Btw you might want to go to Tools->Options->Projects and Solutions->VC++ Directories->Include files, and add the directory for the WTL81 installation to the list (for all platforms) - Mehrdad 2012-04-04 04:48


4

No. The Win32 API doesn't include code to resize and reposition controls. You have to write your own or use a library. Microsoft offers a resource editor in Visual Studio, and MFC (a C++ wrapper around the API), but neither of those address your actual problem (resize and reposition automatically) either. I have used wxWidgets, which is a lot more coherent than MFC (in my opinion) and has a concept called "sizers" which does address resize and reposition.

2012-04-04 03:09
by Bill Forster
Thanks for clarifying - Nathan McCrina 2012-04-04 03:14


3

Here and here you can find a couple of good time-proven examples how to do it. No need to reinvent the wheel.

2012-04-04 03:44
by Flot2011


1

You may need to look into MFC which is a wrapper around win32 which will hide most of the difficult part in GUI designing. It will provide you an resource editor where you can create and position your controls in a form as WYSIWYG.

2012-04-04 02:59
by Jeeva
I wasn't aware the MFC included a high-level control layout manager. I though that it doesn't really help with repositioning controls after a resize - André Caron 2012-04-04 03:07
Positioning != Layou - Mehrdad 2012-04-04 03:09
Ads