2012-04-04 111 views
11

我有一種抽象問題,關於使用直接Win32進行GUI編程。由於我以前的GUI經歷是使用Swing在Java中進行的,因此我習慣於讓佈局管理器在調整窗口大小時自動調整/重新定位按鈕和內容。是否有類似的內置到Win32 API中,或者是否需要在每次重繪時使用絕對位置手動重新計算大小和位置?我認爲這實際上是做這件事的方式,因爲我沒有偶然發現任何看起來像MSDN文檔中的佈局管理的東西,但正如那些(在我看來)有點迷糊的我可能錯過了它。在Win32 GUI程序中的佈局

感謝您的幫助!

+0

我有一些可能適用於純Win32 API調用的MFC代碼:http://stackoverflow.com/a/5739620/5987 – 2012-04-04 03:43:06

回答

1

你可能需要看看MFC這是一個win32的包裝,它將隱藏GUI設計中的大部分難題。它將爲您提供資源編輯器,您可以在所見即所得的形式中創建和定位控件。

+1

我不知道MFC包含一個高級控制佈局管理器。我雖然這並沒有真正幫助調整大小後重新定位控件。 – 2012-04-04 03:07:19

+0

定位!=佈局 – Mehrdad 2012-04-04 03:09:43

4

編號Win32 API不包含調整控件大小和重新定位的代碼。你必須自己寫或使用一個庫。微軟在Visual Studio中提供了一個資源編輯器,還提供了MFC(一個圍繞API的C++包裝器),但是這兩者都不能解決實際問題(自動調整大小和重新定位)。我已經使用了wxWidgets,它比MFC(在我看來)更加連貫,並且有一個名爲「sizers」的概念,它可以解決調整大小和重新定位的問題。

+0

感謝您澄清! – 2012-04-04 03:14:17

4

你需要看看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 
+1

@NathanMcCrina:ATL實際上只是一個Win32的C++接口/包裝器 - 如果你使用的是C++,如果你使用C風格的API,那麼你會給自己一個很難的時刻 - 它會增加* nothing *和讓你遵循不好的做法(例如很多全局變量,這是一個壞主意,但是很容易犯錯)。至於DirectX:我很確定它們會很好地融合在一起 - 畢竟它與Win32沒有什麼不同,因爲它是一回事。 ATL的完整示例是否有幫助(可能沒有DirectX,只是如何顯示對話框)?我可以做一個對話並告訴你如何,這真的不那麼難。 – Mehrdad 2012-04-04 03:27:05

+0

當然,我不會對例子說不! – 2012-04-04 03:33:54

+0

@NathanMcCrina:查看更新。 – Mehrdad 2012-04-04 04:01:29

3

Here and here你可以找到一些經過時間考驗的例子,如何做到這一點。沒有必要重新發明輪子。