云信duilib之菜单

 

 

菜单是一个特殊的窗口,特殊在 在指定鼠标位置显示,焦点消失时,自动销毁,无任务栏图标等

我们看看,duilib是如何实现这些功能的

 


enum MenuAlignment
{
	eMenuAlignment_Left = 1 << 1,
	eMenuAlignment_Top = 1 << 2,
	eMenuAlignment_Right = 1 << 3,
	eMenuAlignment_Bottom = 1 << 4,
};

 

菜单类

extern const TCHAR* const kMenuElementUIInterfaceName;// = _T("MenuElement);
class CMenuElementUI;
class CMenuWnd : public ui::WindowImplBase
{
public:
	virtual Control* CreateControl(const std::wstring& pstrClass) override;

	enum PopupPosType
	{
		RIGHT_BOTTOM,
		RIGHT_TOP
	};

	CMenuWnd(HWND hParent = NULL);
	void Init(STRINGorID xml, LPCTSTR pSkinType, POINT point, PopupPosType popupPosType = RIGHT_BOTTOM);
    std::wstring GetWindowClassName() const;

    LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual std::wstring GetSkinFolder() override {
		return L"menu";
	}
	virtual std::wstring GetSkinFile() override {
		return m_xml.m_lpstr;
	}

	void Show();

public:
	HWND m_hParent;
	POINT m_BasedPoint;
	PopupPosType m_popupPosType;
	STRINGorID m_xml;
	std::wstring m_sType;
};

 

其中,在Init中,创建菜单窗口

void CMenuWnd::Init(STRINGorID xml, LPCTSTR pSkinType, POINT point, PopupPosType popupPosType)
{
	m_BasedPoint = point;
	m_popupPosType = popupPosType;

	if (pSkinType != NULL)
		m_sType = pSkinType;

	m_xml = xml;
	Create(m_hParent, L"菜单", WS_POPUP, WS_EX_TOOLWINDOW | WS_EX_TOPMOST, true, UiRect());
    // HACK: Don't deselect the parent's caption
    HWND hWndParent = m_hWnd;
    while( ::GetParent(hWndParent) != NULL ) hWndParent = ::GetParent(hWndParent);
    ::ShowWindow(m_hWnd, SW_SHOW);
    ::SendMessage(hWndParent, WM_NCACTIVATE, TRUE, 0L);
}

在HandleMessage中处理焦点消失时 销毁窗口功能

LRESULT CMenuWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if( uMsg == WM_KILLFOCUS )
	{
		Close();
		return 0;
	}
	else if( uMsg == WM_KEYDOWN)
	{
		if( wParam == VK_ESCAPE)
		{
			Close();
		}
	}

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

在show中处理菜单显示位置
 

void CMenuWnd::Show()
{
	MONITORINFO oMonitor = {}; 
	oMonitor.cbSize = sizeof(oMonitor);

	if (m_hParent!=NULL)
	{
		::GetMonitorInfo(::MonitorFromWindow(m_hParent, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
	}else
		::GetMonitorInfo(::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
	UiRect rcWork = oMonitor.rcWork;
	UiRect monitor_rect = oMonitor.rcMonitor;
	ui::CSize szInit = { rcWork.right - rcWork.left, rcWork.bottom - rcWork.top };
	szInit = GetRoot()->EstimateSize(szInit);
	szInit.cx -= GetShadowCorner().left + GetShadowCorner().right;
	szInit.cy -= GetShadowCorner().top + GetShadowCorner().bottom;
	if (m_popupPosType == RIGHT_BOTTOM)
	{
		if (m_BasedPoint.y + szInit.cy > monitor_rect.bottom)
		{
			m_BasedPoint.y -= szInit.cy;
		}
	}
	else if (m_popupPosType == RIGHT_TOP)
	{
		if (m_BasedPoint.y - szInit.cy >= monitor_rect.top)
		{
			m_BasedPoint.y -= szInit.cy;
		}
	}
	else
	{
		ASSERT(FALSE);
	}
	UiRect rc;
	rc.left = m_BasedPoint.x;
	rc.top = m_BasedPoint.y;
	if (rc.top < monitor_rect.top)
	{
		rc.top = monitor_rect.top;
	}

	//判断是否超出屏幕
	if (rc.left > monitor_rect.right - szInit.cx)
	{
		rc.left = monitor_rect.right - szInit.cx;
	}
	if (rc.left < monitor_rect.left)
	{
		rc.left = monitor_rect.left;
	}
	rc.right = rc.left + szInit.cx;
	rc.bottom = rc.top + szInit.cy;

	SetPos(rc, SWP_SHOWWINDOW, HWND_TOPMOST, false);
	SetForegroundWindow(m_hWnd);
}

 

在CreateControl中处理菜单元素

Control* CMenuWnd::CreateControl(const std::wstring& pstrClass)
{
	if (pstrClass == kMenuElementUIInterfaceName)
	{
		return new CMenuElementUI();
	}
	return NULL;
}

 

下面再看看菜单元素类

 

class ListContainerElement;
class CMenuElementUI : public ListContainerElement
{
	friend CMenuWnd;
public:
    CMenuElementUI();
	~CMenuElementUI();

	virtual bool ButtonUp(EventArgs& msg) override;
};


//其中,ListContainerElement继承自盒子选项
class UILIB_API ListContainerElement : public OptionTemplate
{
public:
    ListContainerElement();

    int GetIndex() const;
    void SetIndex(int iIndex);

    IListOwner* GetOwner();
    void SetOwner(IListOwner* pOwner);
    void SetVisible(bool bVisible = true);
	void Selected(bool bSelect, bool trigger) override;
	void InvokeDoubleClickEvent();

    virtual void HandleMessage(EventArgs& event) override;

	void AttachDoubleClick(const EventCallback& callback)
	{
		OnEvent[kEventMouseDoubleClick] += callback;
	}

	void AttachReturn(const EventCallback& callback)
	{
		OnEvent[kEventReturn] += callback;
	}

protected:
    int m_iIndex;
    IListOwner* m_pOwner;
};

//再往上翻


template
class UILIB_API OptionTemplate : public CheckBoxTemplate
{
public:
	OptionTemplate();
	~OptionTemplate();
		
	virtual void SetWindow(Window* pManager, Box* pParent, bool bInit = true) override;

	virtual void SetAttribute(const std::wstring& pstrName, const std::wstring& pstrValue) override;
	void SetGroup(const std::wstring& pStrGroupName);
	std::wstring GetGroup() const;
	virtual void Selected(bool bSelected, bool bTriggerEvent = false) override;
	virtual void Activate() override;

protected:
	std::wstring	m_sGroupName;
};


#include "OptionImpl.h"

typedef OptionTemplate Option;
typedef OptionTemplate OptionBox;

//继续翻
template
class UILIB_API CheckBoxTemplate : public ButtonTemplate
{
public:
	CheckBoxTemplate();

	virtual void Activate() override;

	std::wstring GetSelectedStateImage(ControlStateType stateType);
	void SetSelectedStateImage(ControlStateType stateType, const std::wstring& pStrImage);

	void SetSelectedTextColor(const std::wstring& dwTextColor);
	std::wstring GetSelectedTextColor();

	void SetSelectedStateColor(ControlStateType stateType, const std::wstring& stateColor);
	std::wstring GetSelectStateColor(ControlStateType stateType);

	std::wstring GetSelectedForeStateImage(ControlStateType stateType);
	void SetSelectedForeStateImage(ControlStateType stateType, const std::wstring& pStrImage);

	bool IsSelected() const;
	virtual void Selected(bool bSelected, bool bTriggerEvent = false);

	virtual void SetAttribute(const std::wstring& pstrName, const std::wstring& pstrValue) override;

	virtual void PaintStatusColor(HDC hDC) override;
	virtual void PaintStatusImage(HDC hDC) override;
	virtual void PaintText(HDC hDC) override;

	virtual Image* GetEstimateImage() override;

	void AttachSelect(const EventCallback& callback)
	{
		OnEvent[kEventSelect] += callback;
	}

	void AttachUnSelect(const EventCallback& callback)
	{
		OnEvent[kEventUnSelect] += callback;
	}

protected:
	bool			m_bSelected;
	std::wstring	m_dwSelectedTextColor;
	StateColorMap	m_selectedColorMap;
};

其中,有个AttachSelect, 绑定事件,  就是选中菜单某项时,要执行的事件,后续我们使用这个来绑定菜单元素选中时,要执行的函数

菜单元素类源码:

// MenuElementUI
const TCHAR* const kMenuElementUIInterfaceName = _T("MenuElement");

CMenuElementUI::CMenuElementUI()
{
	m_bMouseChildEnabled = false;
}

CMenuElementUI::~CMenuElementUI()
{}

bool CMenuElementUI::ButtonUp(EventArgs& msg)
{
	std::weak_ptr weakFlag = m_pWindow->GetWeakFlag();
	bool ret = __super::ButtonUp(msg);
	if (ret && !weakFlag.expired()) {
		m_pWindow->Close();
	}
	
	return ret;
}

 

菜单的具体使用

1 )菜单位置

  • 点击某按钮跳出菜单
//点击按钮,跳出菜单
bool MyClassForm::UserMenuBtnClick(ui::EventArgs* param){

	RECT rect = param->pSender->GetPos();
	CPoint pt;
	pt.x = rect.left - 65;
	pt.y = rect.bottom + 10;
	ClientToScreen(m_hWnd, &pt);
	PopupUserMenu(pt);

	return true;
}
  • 右键跳出菜单
	if (uMsg==WM_RBUTTONDOWN)
	{

		int xPos = LOWORD(lParam);
		INT yPos = HIWORD(lParam);
	
		CPoint pt;
		pt.x = xPos;
		pt.y = yPos;
		ClientToScreen(m_hWnd, &pt);

		PopupUserMenu(pt);

		return 1;


	}

2)创建并显示菜单

PopupUserMenu(POINT point){


	CMenuWnd* pMenu = new CMenuWnd(m_hWnd);
	STRINGorID xml(L"myClass_user_menu.xml");

	pMenu->Init(xml, _T("xml"), point);

	CMenuElementUI *pUserExit = (CMenuElementUI*)pMenu->FindControl(L"userExit");
	pUserExit->AttachSelect(nbase::Bind(&MyClassForm::MenuItemClick_UserExit, this, std::placeholders::_1));
	
	CMenuElementUI *pFreshClass = (CMenuElementUI*)pMenu->FindControl(L"freshClass");
	pFreshClass->AttachSelect(nbase::Bind(&MyClassForm::MenuItemClick_FreshClass, this, std::placeholders::_1));

	
	CMenuElementUI *pAbout = (CMenuElementUI*)pMenu->FindControl(L"xnwAbout");
	pAbout->AttachSelect(nbase::Bind(&MyClassForm::MenuItemClick_About, this, std::placeholders::_1));


	//CMenuElementUI *pSendLog = (CMenuElementUI*)pMenu->FindControl(L"sendLog");
	//pSendLog->AttachSelect(nbase::Bind(&MyClassForm::MenuItemClick_SendLog, this, std::placeholders::_1));

	//

	CMenuElementUI *pClassSet = (CMenuElementUI*)pMenu->FindControl(L"ClassSet");
	pClassSet->AttachSelect(nbase::Bind(&MyClassForm::MenuItemClick_ClassSet, this, std::placeholders::_1));


	pMenu->Show();
	pMenu->SetFocus(NULL);
}

3)菜单XML布局




    
      
           
      

        
            
    

//控制选中 菜单项时 对应的颜色状态

 

你可能感兴趣的:(duilib界面)