我有一个关于使用直接 Win32 进行 GUI 编程的抽象问题。由于我之前唯一的 GUI 经验是在 Java 中使用 Swing,因此我习惯于拥有一个布局管理器,该管理器会在调整窗口大小时自动调整按钮和内容的大小/重新定位。Win32 API 中是否内置了类似的东西,或者是否必须在每次重绘时使用绝对位置手动重新计算大小和位置?我认为这实际上是实现它的方法,因为我没有偶然发现任何看起来像 MSDN 文档中的布局管理的东西,但因为那些(在我看来)有点迷宫,我可能错过了它。
谢谢你的帮助!
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
不,Win32 API 不包含调整控件大小和重新定位控件的代码。您必须自己编写或使用库。Microsoft 在 Visual Studio 和 MFC(围绕 API 的 C++ 包装器)中提供了资源编辑器,但它们都不能解决您的实际问题(自动调整大小和重新定位)。我使用了 wxWidgets,它比 MFC 更加连贯(在我看来),并且有一个称为“sizers”的概念,它确实解决了调整大小和重新定位的问题。
您可能需要查看MFC,它是 win32 的包装器,它将隐藏 GUI 设计中的大部分困难部分。它将为您提供一个资源编辑器,您可以在其中以所见即所得的形式创建和定位控件。