사용자 도구

사이트 도구


kb:wtl

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:wtl [2014/11/07 14:19] (현재)
줄 1: 줄 1:
 +====== Windows Template Library ======
 +http://​sourceforge.net/​projects/​wtl/​
 +
 +윈도우즈 애플리케이션 및 UI 컴포넌트 개발을 위한 C++ 라이브러리. ATL을 기반으로 개발되었으며,​ 각종 컨트롤, 대화창, 윈도우 프레임, GDI 오브젝트 등을 제공한다.
 +
 +API로 GUI 프로그래밍하려니 귀찮고, MFC를 쓰자니 의존성이 짜증나는 경우, 대안으로 사용할 수 있다. 템플릿 기반으로 작성되었고,​ 특별한 DLL 같은 것을 필요로 하지 않는다. 문제는 관련 문서가 너무 부족하다는 것이다. 공식적인 헬프 파일도 존재하지 않고, 인터넷에 있는 문서들도 MFC 같은 것에 비하면 거의 없는 것과 마찬가지다.
 +
 +장단점을 요약해 보자면 다음과 같다.
 +
 +from http://​discuss.fogcreek.com/​joelonsoftware/​default.asp?​cmd=show&​ixPost=18197
 +
 +I built a couple of medium sized GUI apps with WTL.
 +
 +My experience was generally positive, but I had been using ATL for at least four years by that point, and considered something of an expert in it. With that background, WTL was a breath of fresh air to me compared to the MFC prison.
 +
 +The plus side of WTL:
 +  * Designed like ATL rather than MFC. Functionality is composed via multiple inheritance in a shallow hierarchy rather than using a deep single-inheritance hierarchy where the functionality you want isn't in the branch you need it (What do you mean I need a view to have scrolling support?)
 +  * All source code is available, and it's quite readable if you understand ATL. This also alleviates the "end of life" arguments - who cares if it doesn'​t get maintained? You've got the source code, and it's easy to tweak.
 +  * Since WTL is built around composition,​ it's dirt simple to extend to do whatever you need to.
 +  * Support from WTL's author is quite good - there'​s a WTL yahoo group that he hangs out on.
 +
 +Down sides of WTL:
 +  * If you don't know ATL, or are afraid of templates, stay away. It won't make any sense at all.
 +  * Documentation is essentially non-existant. There'​s a good intro article (2 parts) on http://​www.develop.com somewhere that explains the basics of what's in the library and how to use it. http://​www.codeproject.com has a WTL section with some good stuff. But there'​s no books and no printed articles and no likelyhood of any appearing any time soon.
 +  * Very slow compile times. Lots of templates mean lots of work for the compiler.
 +
 +In general, WTL is the expert'​s tool. If you know Win32 programming well, and understand how ATL is put together, WTL will make you VERY productive, even without the handholding of wizards. If you aren'​t,​ well, you're in for a bit of a tough road. But the destination is well worth it.
 +
 +On the other hand, if you just want to churn out a couple of dialogs, use WinForms instead. ​
 +
 +
 +====== 시작하기 ======
 +  * 라이브러리 이름이 말해주듯이 "​template"​ 라이브러리이기 때문에 헤더 파일만 있으면 만사 OK다. 배포본을 다운로드받아 적당한 곳에다 압축을 푼 다음, Visual C++ > Tools -> Option 으로 가서 include 디렉토리를 설정해 주면 끝이다.
 +  * 위자드를 추가하기 위해서는 배포본 압축 푼 곳에 가보면 appwiz 라는 디렉토리가 있을 것이다. 그 안에 있는 스크립트 파일(setupXX.js)을 해당하는 Visual C++ 버전에 맞춰서 실행하면 끝.
 +
 +
 +====== 팁 ======
 +===== - 리스트뷰 컨트롤 Full Row Select 켜기 =====
 +<code cpp>
 +myListCtrl.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);​
 +</​code>​
 +API를 모르니 원...
 +
 +===== - 모달 다이얼로그 컨트롤 리사이징 =====
 +<code cpp>
 +class cMainDialog : public CDialogImpl<​cMainDialog>,​
 +                    public CDialogResize<​cMainDialog>​ // !!!
 +{
 +    ...
 +    BEGIN_MSG_MAP_EX(cMainDialog)
 +        MSG_WM_INITDIALOG(OnInitDialog)
 +        ...
 +        CHAIN_MSG_MAP(CDialogResize<​cMainDialog>​) // !!!
 +    END_MSG_MAP()
 +
 +    // !!!
 +    BEGIN_DLGRESIZE_MAP(cMainDialog)
 +        DLGRESIZE_CONTROL(IDC_GEOMETRY_GROUP,​ DLSZ_SIZE_X)
 +        DLGRESIZE_CONTROL(IDC_LEVEL_EDIT,​ DLSZ_SIZE_X)
 +        DLGRESIZE_CONTROL(IDC_LEVEL_BUTTON,​ DLSZ_MOVE_X)
 +        DLGRESIZE_CONTROL(IDC_GEOMETRY_EDIT,​ DLSZ_SIZE_X)
 +        DLGRESIZE_CONTROL(IDC_GEOMETRY_BUTTON,​ DLSZ_MOVE_X)
 +    END_DLGRESIZE_MAP()
 +
 +    LRESULT OnInitDialog(HWND hwndFocus, LPARAM lParam)
 +    {
 +        ...
 +        DlgResize_Init(true,​ true, WS_THICKFRAME); ​ // !!!
 +        ...
 +    }
 +};
 +</​code>​
 +
 +===== - ClientEdge 그리기 =====
 +딱히 ATL/WTL 과 관련된 것도 아니고, 윈도우 생성할 때 WS_EX_CLIENTEDGE 플래그 주면 그만인 내용이지만...
 +<code cpp>
 +CRect client, tmp;
 +GetClientRect(&​client);​
 +
 +CBrush light, face, shadow, black;
 +light.CreateSolidBrush(::​GetSysColor(COLOR_BTNHIGHLIGHT));​
 +face.CreateSolidBrush(::​GetSysColor(COLOR_BTNFACE));​
 +shadow.CreateSolidBrush(::​GetSysColor(COLOR_BTNSHADOW));​
 +black.CreateSolidBrush(::​GetSysColor(COLOR_3DDKSHADOW));​
 +
 +// top
 +tmp.SetRect(client.left,​ client.top, client.right - 1, client.top + 1);
 +dc.FillRect(tmp,​ shadow);
 +tmp.SetRect(client.left,​ client.top + 1, client.right - 1, client.top + 2); 
 +dc.FillRect(tmp,​ black);
 +
 +// bottom
 +tmp.SetRect(client.left,​ client.bottom - 2, client.right - 1, client.bottom - 1);
 +dc.FillRect(tmp,​ face);
 +tmp.SetRect(client.left,​ client.bottom - 1, client.right - 1, client.bottom - 0);
 +dc.FillRect(tmp,​ light);
 +
 +// left
 +tmp.SetRect(client.left,​ client.top + 1, client.left + 1, client.bottom - 1);
 +dc.FillRect(tmp,​ shadow);
 +tmp.SetRect(client.left + 1, client.top + 1, client.left + 2, client.bottom - 2);
 +dc.FillRect(tmp,​ black);
 +
 +// right
 +tmp.SetRect(client.right - 2, client.top + 1, client.right - 1, client.bottom - 2);
 +dc.FillRect(tmp,​ face);
 +//​tmp.SetRect(client.right - 2, client.top + 1, client.right - 1, client.bottom - 2);
 +//​dc.FillRect(tmp,​ shadow);
 +
 +// center
 +tmp.SetRect(client.left + 2, client.top + 2, client.right - 2, client.bottom - 2);
 +dc.FillSolidRect(tmp,​ ::​GetSysColor(COLOR_APPWORKSPACE));​
 +</​code>​
 +
 +===== - Contained Window =====
 +<code cpp>
 +class cMainWindow : public cWindowImpl<​...>​
 +{
 +private:
 +    CContainedWindowT<​CEdit>​ m_Edit;
 +
 +public:
 +    BEGIN_MSG_MAP(cMainWindow)
 +        ...
 +    ALT_MSG_MAP(1)
 +        MESSAGE_HANDLER(WM_CHAR,​ OnEditChar)
 +    END_MSG_MAP()
 +
 +    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
 +    {
 +        ...
 +        if (!m_Edit.Create(this,​ 1, m_hWnd, rcDefault))
 +            return -1;
 +        ...
 +    }
 +
 +    LRESULT OnEditChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
 +    {
 +        ...
 +    }
 +};
 +</​code>​
 +메시지맵 ID에 주의
 +
 +===== - 더블 버퍼링 =====
 +CDoubleBufferImpl 클래스를 상속받으면 된다. 그런데 약간 이상한게 CDoubleBufferImpl 클래스 내부에 OnPaint 함수와 메시지맵이 정의가 되어있는데,​ OnPaint 함수가 제대로 호출되지 않는다. 그러므로 실제 상속받은 클래스에서 한번 선언해준다.
 +<code cpp>
 +class cMainDialog : public CDialogImpl<​cMainDialog>,​
 +                    public CDoubleBufferImpl<​cMainDialog>​
 +{
 +public:
 +    enum { IDD = IDD_MAIN };
 +
 +    BEGIN_MSG_MAP_EX(cMainDialog)
 +        ...
 +        MESSAGE_HANDLER(WM_PAINT,​ OnPaint) // 메시지맵은 정의하되,​ 실제 함수는 선언하지 않아야한다.
 +        ...
 +    END_MSG_MAP()
 +
 +    void DoPaint(CDCHandle dc)
 +    {
 +        // 여기서 뭔가를 실제로 그려준다.
 +        ...
 +    }
 +};
 +</​code>​
 +
 +===== - IDLE 처리 =====
 +CIdleHandler 클래스는 기본적으로 idle 처리를 한번 한 후에는 WM_MOUSEMOVE,​ WM_PAINT 이외의 메시지가 도착해야만 다시 idle 처리를 한다. 항상 idle 처리를 하게 만들기 위해서는 클래스를 상속받는 것이 편하다.
 +<code cpp>
 +class cMainFrame : public CFrameWindowImpl<​cMainFrame>, ​
 +                   ​public CUpdateUI<​cMainFrame>,​
 +                   ​public CMessageFilter,​
 +                   ​public CIdleHandler
 +{
 +    ...
 +    virtual BOOL OnIdle()
 +    {
 +        // 여기서 할 일을 정의한다.
 +
 +        return TRUE; // 별 의미 없다.
 +    }
 +    ...
 +};
 +
 +class cCustomMessageLoop : public CMessageLoop
 +{
 +public:
 +    virtual BOOL OnIdle(int nIdleCount)
 +    {
 +        CMessageLoop::​OnIdle(nIdleCount);​
 +
 +        // 리턴값이 중요하다! CMessageLoop::​OnIdle 함수는 기본적으로 FALSE를 반환한다.
 +        return TRUE; 
 +    }
 +};
 +
 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, ​
 +                   ​LPTSTR lpCmdLine, int nCmdShow)
 +{
 +    cCustomMessageLoop theLoop;
 +    cMainFrame theWindow;
 +
 +    theModule.Init(NULL,​ hInstance);
 +    theModule.AddMessageLoop(&​theLoop);​
 +    ​
 +    ....
 +    ​
 +    return 0;
 +}
 +</​code>​
 +
 +===== - Custom Modal Dialog =====
 +CDialogImpl 클래스를 상속받은 모달 Dialog를 만든 경우, Dialog 속성 창에서 Style을 Popup으로 해줘야 정상적으로 동작한다.
 +
 +===== - DDX =====
 +  DDX_FLOAT 매크로를 사용하기 위해서는 atlddx.h 파일을 include하기 전에 _ATL_USE_DDX_FLOAT 매크로를 정의해줘야한다.
 +
 +===== - 메뉴 업데이트 =====
 +메뉴 업데이트(활성화/​비활성화,​ 체크 등)를 사용하기 위해서는 CUpdateUI를 상속받은 다음, BEGIN_UPDATE_UI_MAP,​ END_UPDATE_UI_MAP 맵을 정의해줘야한다. 실제 업데이트는 UIEnable, UISetCheck 등의 함수를 이용한다.
 +<​code>​
 +class cMainFrame : public CFrameWindowImpl<​cMainFrame>, ​
 +                   ​public CUpdateUI<​cMainFrame>,​
 +                   ​public CMessageFilter,​
 +                   ​public CIdleHandler
 +{
 +    BEGIN_UPDATE_UI_MAP(cMainFrame)
 +        UPDATE_ELEMENT(ID_VIEW_ORIGINALMESH,​ UPDUI_MENUPOPUP)
 +        UPDATE_ELEMENT(ID_VIEW_NAVIGATIONMESH,​ UPDUI_MENUPOPUP)
 +        UPDATE_ELEMENT(ID_VIEW_WIREFRAME,​ UPDUI_MENUPOPUP)
 +        UPDATE_ELEMENT(ID_VIEW_BODY,​ UPDUI_MENUPOPUP)
 +    END_UPDATE_UI_MAP()
 +};
 +</​code>​
 +
 +===== - 단축키 =====
 +  * 단축키를 지원하기 위해서는 CMessageFilter를 상속받고,​ PreTranslateMessage>​ 함수를 오버라이드해준 다음, 윈도우 생성 시에 AddMessageFilter 함수를 이용해 메시지 루프에다 필터를 추가해야한다.
 +
 +===== - RichEdit 컨트롤 사용하기 =====
 +RichEdit 컨트롤을 사용하기 위해서는 다음과 같은 매크로를 atlctrls.h 파일을 include 하기 전에 정의하고,​ 어딘가에서 라이브러리를 직접 로드해줘야한다.
 +<code cpp>
 +// RichEdit 1.0을 사용하기 위한 정의
 +//#define WINVER 0x0400
 +//#define _WIN32_IE 0x0400
 +//#define _RICHEDIT_VER 0x0100
 +
 +// RichEdit 2.0을 사용하기 위한 정의
 +#define WINVER ​         0x0500
 +#define _WIN32_WINNT ​   0x0500
 +#define _WIN32_IE ​      ​0x0501
 +#define _RICHEDIT_VER ​  ​0x0200
 +
 +#include <​atlctrls.h>​
 +
 +...
 +
 +HINSTANCE hInstRich = ::​LoadLibrary(CRichEditCtrl::​GetLibraryName());​
 +ATLASSERT(hInstRich != NULL);
 +
 +...
 +
 +::​FreeLibrary(hInstRich);​
 +</​code>​
 +
 +
 +====== 링크 ======
 +  * [[http://​sourceforge.net/​projects/​wtl/​]]
 +    * 오피셜 사이트
 +  * [[http://​www.gamedev.net/​reference/​articles/​article2042.asp | GameDev.net > Using the Windows Template Library Part 1]]
 +  * [[http://​www.gamedev.net/​reference/​articles/​article2161.asp | GameDev.net > Using the Windows Template Library Part 2]]
 +  * [[http://​www.codeproject.com/​wtl/​]]
 +    * [[http://​www.codeproject.com/​wtl/​WTL4MFC1.asp | WTL for MFC Programmers,​ Part I - ATL GUI Classes]]
 +    * [[http://​www.codeproject.com/​wtl/​WTL4MFC2.asp | WTL for MFC Programmers,​ Part II - WTL GUI Base Classes]]
 +    * [[http://​www.codeproject.com/​wtl/​WTL4MFC3.asp | WTL for MFC Programmers,​ Part III - Toolbars and Status Bars]]
 +    * [[http://​www.codeproject.com/​wtl/​WTL4MFC4.asp | WTL for MFC Programmers,​ Part IV - Dialogs and Controls]]
 +    * [[http://​www.codeproject.com/​wtl/​WTL4MFC5.asp | WTL for MFC Programmers,​ Part V - Advanced Dialog UI Classes]]
 +    * [[http://​www.codeproject.com/​wtl/​wtl4mfc6.asp | WTL for MFC Programmers,​ Part VI - Hosting ActiveX Controls]]
 +    * [[http://​www.codeproject.com/​wtl/​wtl4mfc7.asp | WTL for MFC Programmers,​ Part VII - Splitter Windows]]
 +    * [[http://​www.codeproject.com/​wtl/​WTL4MFC8.asp | WTL for MFC Programmers,​ Part VIII - Property Sheets and Wizards]]
 +    * [[http://​www.codeproject.com/​wtl/​wtl4mfc9.asp | WTL for MFC Programmers,​ Part IX - GDI Classes, Common Dialogs, and Utility Classes]]
 +  * [[http://​www.pnotepad.org/​articles/​wtljoys.html | The Joys of WTL]]
 +  * [[http://​www.viksoe.dk/​code/​wtldoc.htm]]
 +    * 7.5 기준의 문서를 ZIP 파일로 다운로드받을 수 있다. 아직 작업이 진행중.
  
kb/wtl.txt · 마지막으로 수정됨: 2014/11/07 14:19 (바깥 편집)