Макет в программе Win32 GUI

У меня есть своего рода абстрактный вопрос об использовании прямого программирования Win32 для GUI. Поскольку мой единственный предыдущий опыт работы с графическим интерфейсом был в Java с использованием Swing, я привык иметь диспетчер компоновки, который автоматически изменяет размеры/перетаскивает кнопки и прочее при изменении размера окна. Есть ли что-то подобное, которое встроено в API Win32, или нужно вручную пересчитать размеры и позиции, используя абсолютные местоположения при каждой перерисовке? Я предполагаю, что это на самом деле способ сделать это, потому что я не наткнулся на все, что выглядит как управление макетами в документах MSDN, но поскольку это (на мой взгляд) немного лабиринт, возможно, я пропустил его.

Спасибо за вашу помощь!

Ответ 1

Нет. API Win32 не включает код для изменения размера и изменения элементов управления. Вы должны написать свой собственный или использовать библиотеку. Microsoft предлагает редактор ресурсов в Visual Studio и MFC (обертка С++ вокруг API), но ни одна из этих проблем не затрагивает вашу актуальную проблему (изменение размера и перестановка автоматически). Я использовал wxWidgets, который намного более согласован, чем MFC (на мой взгляд), и имеет концепцию под названием "sizers", которая решает изменение размера и репозицию.

Ответ 2

Вам нужно взглянуть на ATL (поставляется с Visual С++) и, соответственно, WTL (не поставляется, необходимо загрузить).

Они компилируются почти полностью на "прямой Win32", обеспечивая при этом привлекательную С++-оболочку. Они очень легкие (практически нет веса, на самом деле - прямо Win32 для 99% вызовов), и все же WTL предназначен для имитации функций MFC, поэтому он все еще довольно функциональный.

Однако вам нужно быть полу-хорошим с С++.

Самый простой способ - использовать 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

Ответ 3

Здесь и здесь вы можете найти пару хорошо зарекомендовавшие себя примеры, как это сделать. Нет необходимости изобретать велосипед.

Ответ 4

Вам может потребоваться изучить MFC, который является оберткой вокруг win32, которая скроет большую часть сложной части проектирования графического интерфейса. Он предоставит вам редактор ресурсов, в котором вы можете создавать и размещать свои элементы управления в форме WYSIWYG.