DuiLibの基本フレームワークの機能解析

1. デュリブの紹介

中国初のオープンソースのdirectuiインターフェイス ライブラリで、WYSIWYG 開発ツールであるUIDesignerを提供します。メイン フレーム ウィンドウのみを持ち、残りのスペースは描画によって実現されるため、コントロールのハンドルやウィンドウ クラスはありません。UIDesigner ツールを通じてユーザー定義のウィンドウを xml ファイルに保存し、ウィンドウの作成時に xml ファイルの内容を読み取り、対応するコントロール描画ます現在、duilibで書かれたインターフェースが数多く存在しており、インターネットにアクセスして関連情報を収集することができます。

2. 基本フレームウィンドウ

まず、 Win32系のプロジェクトを新規作成し、main関数を追加します。次に、新しいクラスを作成します。これをCDuiFrameWndと呼びます。クラスのソース コードは次のとおりです。

//头文件
#include <DuiLib\UIlib.h>
using namespace DuiLib;
class CDuiFrameWnd :public CWindowWnd{
    
    
public:
    CDuiFrameWnd();
    ~CDuiFrameWnd();
    virtual LPCTSTR GetWindowClassName() const;
    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
    CPaintManagerUI m_PaintManager;
};
//cpp文件
LPCTSTR CDuiFrameWnd::GetWindowClassName() const
{
    
    
    return _T("DuiFrameWnd");
}
LRESULT CDuiFrameWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    
    
    LRESULT lRes = 0;
    if (WM_CLOSE == uMsg)
    {
    
    
        ::CloseWindow(m_hWnd);
        ::DestroyWindow(m_hWnd);
    }

    if (WM_DESTROY == uMsg)
    {
    
    
        ::PostQuitMessage(0);
    }
    return __super::HandleMessage(uMsg, wParam, lParam);
}

対応する dll ファイルを使用できるようにするには、対応する lib ファイルをインポートする必要もあります。パブリック ヘッダー ファイルに次のコードを追加します。

#ifdef _DEBUG
#   ifdef _UNICODE
#       pragma comment(lib, "Duilib_ud.lib")
#   else
#       pragma comment(lib, "Duilib_d.lib")
#   endif
#else
#   ifdef _UNICODE
#       pragma comment(lib, "Duilib_u.lib")
#   else
#       pragma comment(lib, "Duilib.lib")
#   endif
#endif

main関数のコードは次のとおりです。

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    
    
    CPaintManagerUI::SetInstance(hInstance);
    CDuiFrameWnd duiFrame;

	//#define UI_WNDSTYLE_FRAME      (WS_VISIBLE | WS_OVERLAPPEDWINDOW)
    duiFrame.Create(NULL, _T("测试"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
    duiFrame.ShowWindow();
    CPaintManagerUI::MessageLoop();
    return 0;
}

これらのコードは、基本的なフレーム ウィンドウの生成に役立ちます。また、duilibwin32 APIのパッケージであるため、 win32プログラミング メソッドを直接使用できることを常に覚えておく必要があります。将来使用されないものがある場合は、win32 API使用して関連関数の記述を完了できます。

3. フレームワークの分析

単一ドキュメントのフレーム ウィンドウを生成できるため、コード内の手順は基本的に純粋なwin32 APIを使用する場合と同じです。そのため、この考え方に従ってフレームの簡単な分析を実行します。

main 関数の最初の部分は、CPaintManagerUI::SetInstance(hInstance);というコードです CPaintManagerUI クラスの関数については、よくわかりません。このクラスの関連コードをよく見ていませんが、この文は主に プロセス のインスタンス ハンドルを取得します今のところは心配しないでください。次の手順は主に、クラスCDuiFrameWndまたはその基本クラスCWindowWndで完了します。

3.1. ウィンドウクラスの作成

main 関数の 2 番目のコードは、主にクラスCDuiFrameWndオブジェクトの作成を完了します。対応するコンストラクターをたどったところ、冗長な操作が行われていないことがわかりました。構築方法に関係なく、次はクラスの Create 関数を呼び出してウィンドウを作成します。この関数のコードは次のとおりです

HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
    
    
    if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
    if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
    m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetInstance(), this);
    ASSERT(m_hWnd!=NULL);
    return m_hWnd;
}

主に 2 番目の if のコードを見てみましょう。まず、親ウィンドウの文字列が NULL で、次にRegisterWindowClass が実行されます。さらにRegisterWindowClassをたどると、そのコードは次のようになります。

bool CWindowWnd::RegisterWindowClass()
{
    
    
    WNDCLASS wc = {
    
     0 };
    wc.style = GetClassStyle();
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIcon = NULL;
    wc.lpfnWndProc = CWindowWnd::__WndProc;
    wc.hInstance = CPaintManagerUI::GetInstance(); //之前设置的实例句柄在这个地方使用
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = GetWindowClassName();
    ATOM ret = ::RegisterClass(&wc);
    ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
    return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

最初に行うべきことはウィンドウ クラスを作成することであり、ウィンドウ クラスを作成する際の主な関心事は、ウィンドウクラスのlpfnWndProcメンバーとlpszClassNameであることがわかりました。lpszClassName は、派生クラスで書き直した関数GetWindowClassNameを呼び出します。そのため、ポリモーフィズムに従って派生クラスのGetWindowClassName関数を呼び出し、指定した文字列をウィンドウ クラスのクラス名として使用します。

3.2. ウィンドウクラスの登録

上記のコードから、登録されたコードもRegisterWindowClassに配置されていることがわかります最後に、RegisterClass 関数が呼び出されて登録が完了します。

3.3. ウィンドウの作成

RegisterWindowClassが実行されると、次のコード、つまりm_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetInstance(), this); が実行され、ウィンドウの作成タスクが完了します

3.4. 表示ウィンドウ

Create関数が実行された後、次のduiFrame.ShowWindow()が実行されます。この関数に従い、関数コードは次のとおりです。

void CWindowWnd::ShowWindow(bool bShow /*= true*/, bool bTakeFocus /*= false*/)
{
    
    
    ASSERT(::IsWindow(m_hWnd));
    if( !::IsWindow(m_hWnd) ) return;
    ::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
}

ShowWindow関数のデフォルトの受信パラメータは bShow = true、bTakeFocus = false です。ShowWindow関数最後に呼び出されるとき、 bShowおよびbTakeFocusに従って渡す価値があります。コードによると、パラメータが渡されない場合、コードShowWindow(m_hWnd, SW_SHOWNOACTIVATE);が必要であることがわかりました。

3.5、メッセージループ

メッセージ ループは実際にはコードCPaintManagerUI::MessageLoop();によって完了します。MessageLoop関数に従って確認します。

    MSG msg = {
    
     0 };
    while( ::GetMessage(&msg, NULL, 0, 0) ) {
    
    
        if( !CPaintManagerUI::TranslateMessage(&msg) ) {
    
    
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
    }

この関数では、メッセージ ループが実行されます。

3.6. コールバック関数

上では、lpfnWndProc関数ポインターについては言及せずにそのままにしました。次に、この部分を説明し、対応するコンストラクターをたどって、クラス自体は操作を行わないが、親クラスのコンストラクターが関連する初期化操作を実行することを確認しましょう。対応するコードは次のとおりです:

CWindowWnd::CWindowWnd() : m_hWnd(NULL), m_OldWndProc(::DefWindowProc), m_bSubclassed(false)
{
    
    
}

これは、デフォルトのメッセージを処理するために、 lpfnWndProc が__WndProc を指すようにします。これは静的ハンドラー関数であり、そのコードは次のとおりです。

LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    
    
    CWindowWnd* pThis = NULL;
    if( uMsg == WM_NCCREATE ) {
    
    
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        //当开始创建窗口将窗口类对象的指针放入到对应的GWLP_USERDATA字段中
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    } 
    else {
    
    
    //取出窗口类对象的指针
        pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
        if( uMsg == WM_NCDESTROY && pThis != NULL ) {
    
    
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
            if( pThis->m_bSubclassed ) pThis->Unsubclass();
            pThis->m_hWnd = NULL;
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }
    if( pThis != NULL ) {
    
    
        return pThis->HandleMessage(uMsg, wParam, lParam);
    } 
    else {
    
    
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

上記のコードでは、ウィンドウの作成時にウィンドウ クラス オブジェクト ポインタが対応する場所に保存されるため、他の場所で取得して使用することができます。return pThis->HandleMessage(uMsg, wParam, lParam);この文によって呼び出される特定のオブジェクトのHandleMessageにより、対応する派生クラスで対応する仮想関数を定義しているため、ポリモーフィズムに従って、特定のメッセージを処理するために書き換えた仮想関数を呼び出します。関心のないメッセージについては、LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, h Wnd) を呼び出します。 、uMsg、wParam、lParam); または DefWindowProc の基本クラスのコンストラクターを確認すると、 m_OldWndProc が実際には DefWindowProc であることがわかりまし

CWindowWnd::CWindowWnd() : m_hWnd(NULL), m_OldWndProc(::DefWindowProc), m_bSubclassed(false)
{
    
    
}

4. まとめ

上記では duilib の基本的なフレームワークを説明しましたが、以下にそれを要約しましょう。

  1. CPaintManagerUI::SetInstance(hInstance) ;プロセスのインスタンス ハンドルを設定します。この値はウィンドウ クラスを登録するときに使用されます。最初に .exe ファイルのパスを設定し、その後で XML のパスを設定します。
  2. CWindowWndクラスではCreate関数によってウィンドウ クラスの作成と登録、およびウィンドウの作成が完了します。
  3. ウィンドウを表示するには、CWindowWndクラスのShowWindow関数を使用します。
  4. メッセージ ループはCPaintManagerUI::MessageLoop() ; コードによって実行されます。
  5. 最後に、関心のあるメッセージを処理するためにHandleMessage()関数を書き直す必要があります。最後に、基本クラスのHandleMessage()関数を呼び出す必要があります。主に、関心のないメッセージを処理するためにDefWindowProcを呼び出します。

おすすめ

転載: blog.csdn.net/qq_44918090/article/details/131767709