在duilib中嵌入win32控件或者MFC控件

    玩duilib的時候在網上看到其餘文章在duilib中嵌入MFC的例子,屢試不行,總是顯示不出MFC控件或者win32控件,後來本身研究了一番,發現問題所在,並拿出來分享一下。 ide

    首先duilib是什麼這裏很少說,自行百度。這個例子效果是這樣的,在dui界面中能夠嵌入win32的按鈕,以下圖:函數

點擊win32按鈕能夠響應消息:ui

 

至於網上其餘教程我試驗不靈光的緣由是,duilib中使用UpdateLayeredWindow來支持窗口的透明效果,就是背景圖片是個帶透明通道的png圖片的時候,就是有半透明漸變陰影的時候設置皮膚文件的屬性bktrans:<Window size="544,394" caption="22,22,22,50" roundcorner="5,5" bktrans="true">this

只要這個是true,添加到主窗口的子窗口都隱藏不可見了。code

 

暫時想到的辦法就是建立一個以桌面爲父窗口的window貼到dui界面上,而後再把須要添加的win32控件之類的加到這個窗口上來。繼承

 

代碼吭哧吭哧擼起來教程

首先咱們這個須要是個dui控件能夠支持皮膚文件編輯的,因此須要繼承CControlUI,我不想像其餘例子那樣另外再建立window而後Attach,這樣很麻煩,那麼再繼承自CWindowWnd就好了,那麼咱們的類看起來是這樣子的接口

class CFrameWndUI : public CControlUI, public CWindowWnd
public:
	CFrameWndUI();
	virtual ~CFrameWndUI();

	LPCTSTR GetWindowClassName() const;

protected:
	virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;

};

GetWindowClassName就返回個窗口類名了圖片

LPCTSTR CFrameWndUI::GetWindowClassName() const
{
    return _T("CFrameWndUI");
}

咱們在構造函數裏爲本身建立一個窗口it

CFrameWndUI::CFrameWndUI()
{
    // 建立一個無標題無邊框的窗口
    Create(NULL, _T("CFrameWndUI"), UI_WNDSTYLE_DIALOG & ~WS_CAPTION,  WS_EX_TOOLWINDOW, 0, 0, 0, 0);
}

要建立無標題的窗口就不能設置WS_CAPTION,擴展樣式裏面WS_EX_TOOLWINDOW爲了讓任務欄不出現窗口圖標,不設置的話,畫面就是這樣

重寫CControlUI的 virtual void DoInit();,在裏面建立3個按鈕

void CFrameWndUI::DoInit()
{
    // 建立win32類型的按鈕
    // 參數HMENU借來傳遞按鈕ID
    CreateWindow(_T("BUTTON"), _T("我是按鈕1"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 0, 80, 30, m_hWnd,
                 (HMENU)IDB_TEST1, CPaintManagerUI::GetInstance(), NULL);

	CreateWindow(_T("BUTTON"), _T("我是按鈕2"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 40, 80, 30, m_hWnd,
		(HMENU)IDB_TEST2, CPaintManagerUI::GetInstance(), NULL);

	CreateWindow(_T("BUTTON"), _T("我是按鈕3"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 80, 80, 30, m_hWnd,
		(HMENU)IDB_TEST3, CPaintManagerUI::GetInstance(), NULL);
}

接下來最重要的是根據主窗口的位置和控件大小設置窗口位置了,給類添加個私有函數AdjustRect,而且覆蓋DoPaint,在DoPaint裏面調用AdjustRect

class CFrameWndUI : public CControlUI, public CWindowWnd
public:
	CFrameWndUI();
	virtual ~CFrameWndUI();

	LPCTSTR GetWindowClassName() const;

	virtual void DoInit();

	virtual void DoPaint(HDC hDC, const RECT& rcPaint);

private:
	void AdjustRect(); // 調整本身的UI大小和座標

};
void CFrameWndUI::AdjustRect()
{
    // 獲取APP客戶端區域
    CDuiRect rcApp;
    GetWindowRect(m_pManager->GetPaintWindow(), &rcApp);

    CDuiRect rcSelf(m_rcItem);

    rcSelf.left += rcApp.left;
    rcSelf.top += rcApp.top;

    // 是不是固定座標
    if(m_bFloat)
    {
        rcSelf.right = m_cxyFixed.cx;
        rcSelf.bottom = m_cxyFixed.cy;
    }

    ::SetWindowPos(m_hWnd, NULL, rcSelf.left, rcSelf.top, rcSelf.right, rcSelf.bottom, SWP_NOACTIVATE);
}

void CFrameWndUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
    __super::DoPaint(hDC, rcPaint);
    AdjustRect();
}

這裏計算代碼很簡單,就是獲取主窗口的座標,而後加上控件座標就是x,y了,當控件是float的時候,控件大小就是修正大小m_cxyFixed,不然就是自適應的大小。

控件如何自動建立就是新建的一個dui界面class CMainWnd : public WindowImplBase,繼承自WindowImplBase就會有個virtual CControlUI* CreateControl(LPCTSTR pstrClass);裏面判斷控件類型,new一個就是了,皮膚文件裏面<FrameWnd name="test" mouse="false" float="true"  pos="100,100,0,0" width="200" height="200" />就是這樣便可

CControlUI* CMainWnd::CreateControl(LPCTSTR pstrClass)
{
	if (_tcsicmp(pstrClass, _T("FrameWnd")) == 0)
	{

		CFrameWndUI  *pUI = new CFrameWndUI();
		      
		return pUI;
	}

	return NULL;
}

 

如今運行看看,有效果了,

而後拖動主窗口看看,發現按鈕並無跟隨窗口移動

這裏咱們須要再添加個處理,監聽主窗口的WM_WINDOWPOSCHANGED消息,方法就是集成一個接口IMessageFilterUI,實現MessageHandler

class CFrameWndUI : public CControlUI, public CWindowWnd, public IMessageFilterUI
{
public:
	CFrameWndUI();
	virtual ~CFrameWndUI();

	LPCTSTR GetWindowClassName() const;

	virtual void DoInit();

	virtual void DoPaint(HDC hDC, const RECT& rcPaint);

	virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled) override;

protected:
	virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;

private:
	void AdjustRect(); // 調整本身的UI大小和座標
};

而後在DoInit註冊消息監聽

void CFrameWndUI::DoInit()
{
    // 添加主窗口消息過濾器
    m_pManager->AddMessageFilter(this);

    ...
}
LRESULT CFrameWndUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
    // 判斷主窗口位置改變就調整窗口
    if(uMsg == WM_WINDOWPOSCHANGED)
    {
        AdjustRect();
    }

    return 0;
}

要處理win32按鈕消息,就是在HandleMessage裏處理WM_COMMAND消息便可

LRESULT CFrameWndUI::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRes = 0;
    BOOL bHandled = FALSE;

    switch(uMsg)
    {
    case WM_COMMAND:
        lRes = OnCommand(uMsg, wParam, lParam, bHandled);
        break;

    default:
        break;
    }

    if(bHandled)
    {
        return lRes;
    }

    return __super::HandleMessage(uMsg, wParam, lParam);
}

 

完整代碼:

#pragma once

/*!
 * @file FrameWndUI.h
 * @date 2017/07/14 14:33
 *
 * @author 阿力
 *
 * @brief 將win32或者MFC的控件嵌入到duilib上面
 *
*/
class CFrameWndUI : public CControlUI, public CWindowWnd, public IMessageFilterUI
{
public:
	CFrameWndUI();
	virtual ~CFrameWndUI();

	LPCTSTR GetWindowClassName() const;

	virtual void DoInit();

	virtual void DoPaint(HDC hDC, const RECT& rcPaint);

	virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled) override;

protected:
	virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;

private:
	void AdjustRect(); // 調整本身的UI大小和座標
	virtual LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};

FrameWndUI.cpp

#include "stdafx.h"
#include "FrameWndUI.h"

static CONST INT IDB_TEST1 = 0x121;
static CONST INT IDB_TEST2 = 0x122;
static CONST INT IDB_TEST3 = 0x123;

CFrameWndUI::CFrameWndUI()
{
    // 建立一個無標題無邊框的窗口
    Create(NULL, _T("CFrameWndUI"), UI_WNDSTYLE_DIALOG & ~WS_CAPTION, WS_EX_LAYERED | WS_EX_TOOLWINDOW, 0, 0, 0, 0);

}

CFrameWndUI::~CFrameWndUI()
{
    if(m_pManager)
    {
        // 移除主窗口消息過濾器
        m_pManager->RemoveMessageFilter(this);
    }
}

LPCTSTR CFrameWndUI::GetWindowClassName() const
{
    return _T("CWndUI");
}

void CFrameWndUI::DoInit()
{
    // 添加主窗口消息過濾器
    m_pManager->AddMessageFilter(this);

    // 建立win32類型的按鈕
    // 參數HMENU借來傳遞按鈕ID
    CreateWindow(_T("BUTTON"), _T("我是按鈕1"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 0, 80, 30, m_hWnd,
                 (HMENU)IDB_TEST1, CPaintManagerUI::GetInstance(), NULL);

	CreateWindow(_T("BUTTON"), _T("我是按鈕2"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 40, 80, 30, m_hWnd,
		(HMENU)IDB_TEST2, CPaintManagerUI::GetInstance(), NULL);

	CreateWindow(_T("BUTTON"), _T("我是按鈕3"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 80, 80, 30, m_hWnd,
		(HMENU)IDB_TEST3, CPaintManagerUI::GetInstance(), NULL);
}

void CFrameWndUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
    __super::DoPaint(hDC, rcPaint);
    AdjustRect();
}

LRESULT CFrameWndUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
    // 判斷主窗口位置改變就調整窗口
    if(uMsg == WM_WINDOWPOSCHANGED)
    {
        AdjustRect();
    }

    return 0;
}

LRESULT CFrameWndUI::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRes = 0;
    BOOL bHandled = FALSE;

    switch(uMsg)
    {
    case WM_COMMAND:
        lRes = OnCommand(uMsg, wParam, lParam, bHandled);
        break;

    default:
        break;
    }

    if(bHandled)
    {
        return lRes;
    }

    return __super::HandleMessage(uMsg, wParam, lParam);
}

void CFrameWndUI::AdjustRect()
{
    // 獲取APP客戶端區域
    CDuiRect rcApp;
    GetWindowRect(m_pManager->GetPaintWindow(), &rcApp);

    CDuiRect rcSelf(m_rcItem);

    rcSelf.left += rcApp.left;
    rcSelf.top += rcApp.top;

    // 是不是固定座標
    if(m_bFloat)
    {
        rcSelf.right = m_cxyFixed.cx;
        rcSelf.bottom = m_cxyFixed.cy;
    }

    ::SetWindowPos(m_hWnd, NULL, rcSelf.left, rcSelf.top, rcSelf.right, rcSelf.bottom, SWP_NOACTIVATE);
}

LRESULT CFrameWndUI::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	switch (LOWORD(wParam))
	{
	case IDB_TEST1:
		::MessageBox(NULL, _T("你點了按鈕1"), _T(""), MB_OK);
		break;
	case IDB_TEST2:
		::MessageBox(NULL, _T("你點了按鈕2"), _T(""), MB_OK);
		break;
	case IDB_TEST3:
		::MessageBox(NULL, _T("你點了按鈕3"), _T(""), MB_OK);
		break;
	default:
		break;
	}

    return 0;
}
相關文章
相關標籤/搜索