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

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

    玩duilib的时候在网上看到其他文章在duilib中嵌入MFC的例子,屡试不行,老是显示不出MFC控件或者win32控件,后来自己研究了一番,发现问题所在,并拿出来分享一下。 

    首先duilib是什么这里不多说,自行百度。这个例子效果是这样的,在dui界面中可以嵌入win32的按钮,如下图:

在duilib中嵌入win32控件或者MFC控件_第1张图片

点击win32按钮可以响应消息:

在duilib中嵌入win32控件或者MFC控件_第2张图片

 

至于网上其他教程我试验不灵光的原因是,duilib中使用UpdateLayeredWindow来支持窗口的透明效果,就是背景图片是个带透明通道的png图片的时候,就是有半透明渐变阴影的时候设置皮肤文件的属性bktrans:

只要这个是true,添加到主窗口的子窗口都隐藏不可见了。

 

暂时想到的办法就是创建一个以桌面为父窗口的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");
}

我们在构造函数里为自己创建一个窗口

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一个就是了,皮肤文件里面就是这样即可

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

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

	return NULL;
}

 

现在运行看看,有效果了,

在duilib中嵌入win32控件或者MFC控件_第3张图片

然后拖动主窗口看看,发现按钮并没有跟随窗口移动

在duilib中嵌入win32控件或者MFC控件_第4张图片

这里我们需要再添加个处理,监听主窗口的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;
}

 

转载于:https://my.oschina.net/u/816723/blog/1377595

你可能感兴趣的:(python,ui)