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!
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
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.
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.