【问题标题】:Layout in Win32 GUI programWin32 GUI程序中的布局
【发布时间】:2012-04-17 18:15:01
【问题描述】:

我有一个关于使用直接 Win32 进行 GUI 编程的抽象问题。由于我之前唯一的 GUI 经验是在 Java 中使用 Swing,因此我习惯于拥有一个布局管理器,该管理器会在调整窗口大小时自动调整按钮和内容的大小/重新定位。 Win32 API 中是否内置了类似的东西,或者是否必须在每次重绘时使用绝对位置手动重新计算大小和位置?我认为这实际上是实现它的方法,因为我没有偶然发现任何看起来像 MSDN 文档中的布局管理的东西,但因为那些(在我看来)有点迷宫,我可能错过了它。

感谢您的帮助!

【问题讨论】:

标签: c++ winapi


【解决方案1】:

您需要查看ATL(Visual C++ 附带)和对应的WTL(未附带,需要下载)。

它们几乎完全编译为“直接 Win32”,同时提供了一个很好的 C++ 包装器。它们非常轻量(几乎没有重量,实际上——99% 的调用都是直接 Win32 的),但 WTL 旨在模仿 MFC 的功能,所以它仍然很有特色。

不过,您需要精通 C++。

最简单的方法是在类似的地方使用CDialogResize<CYourDialog>

// 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() 是布局的核心 -- 例如,DLSZ_MOVE_Y 表示您要垂直移动 IDOK。您也可以将它们分组,但这会变得很棘手(有时我也不明白发生了什么)......但是一旦你做对了,它实际上并没有那么糟糕。 :)


这是一个独立的例子:

#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();
}

要编译它,你还需要一个名为resource.h的文件,其内容如下:

#define IDD_DIALOG1                     101
#define IDR_RT_MANIFEST1                103

还有一个名为Sample.rc 的文件添加到项目中,可以使用Visual Studio 进行编辑,其中包含对话框布局:

#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

【讨论】:

  • @NathanMcCrina:ATL 实际上只是 Win32 的 C++ 接口/包装器——如果你使用 C++,如果你使用 C 风格的 API,你只会给自己带来困难—— - 它添加了nothing 并让您遵循不良做法(例如,大量全局变量,这是一个坏主意,但很容易出错)。至于 DirectX:我很确定它们会很好地结合在一起——毕竟它与 Win32 没有什么不同,因为它是同一件事。 ATL 的完整示例是否有帮助(可能没有 DirectX,只是如何显示对话框)?我可以做一个对话,告诉你怎么做,真的没那么难。
  • 当然,我不会拒绝例子!
  • 非常感谢!我现在正在检查。
  • 我只有 Express 版本,所以显然编译使用 ATL 的项目的唯一方法是安装 Windows Driver Kit;轻微延迟:/
  • @NathanMcCrina:啊,是的,对不起……希望不会太痛苦哈哈。
【解决方案2】:

没有。 Win32 API 不包含调整控件大小和重新定位控件的代码。您必须自己编写或使用库。 Microsoft 在 Visual Studio 和 MFC(围绕 API 的 C++ 包装器)中提供了资源编辑器,但它们都不能解决您的实际问题(自动调整大小和重新定位)。我使用过 wxWidgets,它比 MFC 更连贯(在我看来),并且有一个名为“sizers”的概念,它确实解决了调整大小和重新定位问题。

【讨论】:

  • 自发布此答案以来,情况发生了变化。从 Visual Studio 2015 开始,MFC 确实支持dynamic layout
【解决方案3】:

您可能需要查看MFC,它是一个围绕 win32 的包装器,它将隐藏 GUI 设计中的大部分困难部分。它将为您提供一个资源编辑器,您可以在其中以所见即所得的形式创建和定位控件。

【讨论】:

  • 我不知道 MFC 包含一个高级控件布局管理器。我虽然在调整大小后重新定位控件并没有真正的帮助。
  • @and:确实如此,从 Visual Studio 2015 开始(请参阅 Dynamic Layout)。
猜你喜欢
  • 2012-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-14
  • 2011-09-12
  • 1970-01-01
  • 2018-05-03
  • 2018-07-03
相关资源
最近更新 更多