第二章 第一小节Duilib中的根控件CControlUI
上一章从底层的基础架构上分析duilib采用的核心部件,如解析xml文件为控件树,两条消息传递路线,控件的绘制流程和子控件的查找等等,如果想深入使用duilib,还是应该反复阅读源码的这些部分直到轮廓原理非常清晰。
本章的主要内容是分析duilib提供的各类子控件,使读者真正掌握这些控件,也可以在控件出现bug的时候,快速找到问题。请读者大致浏览下源码,阅读注释,源代码如下:
class UILIB_API CControlUI
{
DECLARE_DUICONTROL(CControlUI)
public:
CControlUI();
virtual ~CControlUI();
public:
virtual CDuiString GetName() const;
virtual void SetName(LPCTSTR pstrName);
virtual LPCTSTR GetClass() const;
virtual LPVOID GetInterface(LPCTSTR pstrName);
virtual UINT GetControlFlags() const;
virtual bool Activate();
virtual CPaintManagerUI* GetManager() const;
virtual void SetManager(CPaintManagerUI* pManager, CControlUI* pParent, bool bInit = true);
virtual CControlUI* GetParent() const;
void setInstance(HINSTANCE instance = NULL) {m_instance = instance;};
// 定时器
bool SetTimer(UINT nTimerID, UINT nElapse);
void KillTimer(UINT nTimerID);
// 文本相关
virtual CDuiString GetText() const;
virtual void SetText(LPCTSTR pstrText);
virtual bool IsResourceText() const;
virtual void SetResourceText(bool bResource);
virtual bool IsDragEnabled() const;
virtual void SetDragEnable(bool bDrag);
virtual bool IsDropEnabled() const;
virtual void SetDropEnable(bool bDrop);
// 图形相关
LPCTSTR GetGradient();
void SetGradient(LPCTSTR pStrImage);
DWORD GetBkColor() const;
void SetBkColor(DWORD dwBackColor);
DWORD GetBkColor2() const;
void SetBkColor2(DWORD dwBackColor);
DWORD GetBkColor3() const;
void SetBkColor3(DWORD dwBackColor);
DWORD GetForeColor() const;
void SetForeColor(DWORD dwForeColor);
LPCTSTR GetBkImage();
void SetBkImage(LPCTSTR pStrImage);
LPCTSTR GetForeImage() const;
void SetForeImage(LPCTSTR pStrImage);
DWORD GetFocusBorderColor() const;
void SetFocusBorderColor(DWORD dwBorderColor);
bool IsColorHSL() const;
void SetColorHSL(bool bColorHSL);
SIZE GetBorderRound() const;
void SetBorderRound(SIZE cxyRound);
bool DrawImage(HDC hDC, LPCTSTR pStrImage, LPCTSTR pStrModify = NULL);
//边框相关
int GetBorderSize() const;
void SetBorderSize(int nSize);
DWORD GetBorderColor() const;
void SetBorderColor(DWORD dwBorderColor);
void SetBorderSize(RECT rc);
int GetLeftBorderSize() const;
void SetLeftBorderSize(int nSize);
int GetTopBorderSize() const;
void SetTopBorderSize(int nSize);
int GetRightBorderSize() const;
void SetRightBorderSize(int nSize);
int GetBottomBorderSize() const;
void SetBottomBorderSize(int nSize);
int GetBorderStyle() const;
void SetBorderStyle(int nStyle);
// 位置相关
virtual RECT GetRelativePos() const; // 相对(父控件)位置
virtual RECT GetClientPos() const; // 客户区域(除去scrollbar和inset)
virtual const RECT& GetPos() const;
virtual void SetPos(RECT rc, bool bNeedInvalidate = true);
virtual void Move(SIZE szOffset, bool bNeedInvalidate = true);
virtual int GetWidth() const;
virtual int GetHeight() const;
virtual int GetX() const;
virtual int GetY() const;
virtual RECT GetPadding() const;
virtual void SetPadding(RECT rcPadding); // 设置外边距,由上层窗口绘制
virtual SIZE GetFixedXY() const; // 实际大小位置使用GetPos获取,这里得到的是预设的参考值
virtual void SetFixedXY(SIZE szXY); // 仅float为true时有效
virtual int GetFixedWidth() const; // 实际大小位置使用GetPos获取,这里得到的是预设的参考值
virtual void SetFixedWidth(int cx); // 预设的参考值
virtual int GetFixedHeight() const; // 实际大小位置使用GetPos获取,这里得到的是预设的参考值
virtual void SetFixedHeight(int cy); // 预设的参考值
virtual int GetMinWidth() const;
virtual void SetMinWidth(int cx);
virtual int GetMaxWidth() const;
virtual void SetMaxWidth(int cx);
virtual int GetMinHeight() const;
virtual void SetMinHeight(int cy);
virtual int GetMaxHeight() const;
virtual void SetMaxHeight(int cy);
virtual TPercentInfo GetFloatPercent() const;
virtual void SetFloatPercent(TPercentInfo piFloatPercent);
virtual void SetFloatAlign(UINT uAlign);
virtual UINT GetFloatAlign() const;
// 鼠标提示
virtual CDuiString GetToolTip() const;
virtual void SetToolTip(LPCTSTR pstrText);
virtual void SetToolTipWidth(int nWidth);
virtual int GetToolTipWidth(void); // 多行ToolTip单行最长宽度
// 光标
virtual WORD GetCursor();
virtual void SetCursor(WORD wCursor);
// 快捷键
virtual TCHAR GetShortcut() const;
virtual void SetShortcut(TCHAR ch);
// 菜单
virtual bool IsContextMenuUsed() const;
virtual void SetContextMenuUsed(bool bMenuUsed);
// 用户属性
virtual const CDuiString& GetUserData(); // 辅助函数,供用户使用
virtual void SetUserData(LPCTSTR pstrText); // 辅助函数,供用户使用
virtual UINT_PTR GetTag() const; // 辅助函数,供用户使用
virtual void SetTag(UINT_PTR pTag); // 辅助函数,供用户使用
// 一些重要的属性
virtual bool IsVisible() const;
virtual void SetVisible(bool bVisible = true);
virtual void SetInternVisible(bool bVisible = true); // 仅供内部调用,有些UI拥有窗口句柄,需要重写此函数
virtual bool IsEnabled() const;
virtual void SetEnabled(bool bEnable = true);
virtual bool IsMouseEnabled() const;
virtual void SetMouseEnabled(bool bEnable = true);
virtual bool IsKeyboardEnabled() const;
virtual void SetKeyboardEnabled(bool bEnable = true);
virtual bool IsFocused() const;
virtual void SetFocus();
virtual bool IsFloat() const;
virtual void SetFloat(bool bFloat = true);
virtual CControlUI* FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags);
void Invalidate();
bool IsUpdateNeeded() const;
void NeedUpdate();
void NeedParentUpdate();
DWORD GetAdjustColor(DWORD dwColor);
virtual void Init();
virtual void DoInit();
virtual void Event(TEventUI& event);
virtual void DoEvent(TEventUI& event);
// 自定义(未处理的)属性
void AddCustomAttribute(LPCTSTR pstrName, LPCTSTR pstrAttr);
LPCTSTR GetCustomAttribute(LPCTSTR pstrName) const;
bool RemoveCustomAttribute(LPCTSTR pstrName);
void RemoveAllCustomAttribute();
virtual void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
CControlUI* ApplyAttributeList(LPCTSTR pstrList);
virtual SIZE EstimateSize(SIZE szAvailable);
virtual bool Paint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl = NULL); // 返回要不要继续绘制
virtual bool DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl);
virtual void PaintBkColor(HDC hDC);
virtual void PaintBkImage(HDC hDC);
virtual void PaintStatusImage(HDC hDC);
virtual void PaintForeColor(HDC hDC);
virtual void PaintForeImage(HDC hDC);
virtual void PaintText(HDC hDC);
virtual void PaintBorder(HDC hDC);
virtual void DoPostPaint(HDC hDC, const RECT& rcPaint);
//虚拟窗口参数
void SetVirtualWnd(LPCTSTR pstrValue);
CDuiString GetVirtualWnd() const;
public:
CEventSource OnInit;
CEventSource OnDestroy;
CEventSource OnSize;
CEventSource OnEvent;
CEventSource OnNotify;
protected:
CPaintManagerUI* m_pManager;
CControlUI* m_pParent;
CDuiString m_sVirtualWnd;
CDuiString m_sName;
bool m_bUpdateNeeded;
bool m_bMenuUsed;
RECT m_rcItem;
RECT m_rcPadding;
SIZE m_cXY;
SIZE m_cxyFixed;
SIZE m_cxyMin;
SIZE m_cxyMax;
bool m_bVisible;
bool m_bInternVisible;
bool m_bEnabled;
bool m_bMouseEnabled;
bool m_bKeyboardEnabled ;
bool m_bFocused;
bool m_bFloat;
TPercentInfo m_piFloatPercent;
UINT m_uFloatAlign;
bool m_bSetPos; // 防止SetPos循环调用
bool m_bDragEnabled;
bool m_bDropEnabled;
bool m_bResourceText;
CDuiString m_sText;
CDuiString m_sToolTip;
TCHAR m_chShortcut;
CDuiString m_sUserData;
UINT_PTR m_pTag;
CDuiString m_sGradient;
DWORD m_dwBackColor;
DWORD m_dwBackColor2;
DWORD m_dwBackColor3;
DWORD m_dwForeColor;
CDuiString m_sBkImage;
CDuiString m_sForeImage;
DWORD m_dwBorderColor;
DWORD m_dwFocusBorderColor;
bool m_bColorHSL;
int m_nBorderSize;
int m_nBorderStyle;
int m_nTooltipWidth;
WORD m_wCursor;
SIZE m_cxyBorderRound;
RECT m_rcPaint;
RECT m_rcBorderSize;
HINSTANCE m_instance;
CStdStringPtrMap m_mCustomAttrHash;
};
源码中的注释已经解释了部分代码的作用,源代码虽然长,但是主要一部分是事件的响应,另一部分是控件的绘制,前一部分在消息循环中已经讲解,在这小节中,集中讲解控件的绘制,如果需要开发自定义控件和熟悉控件的使用,对这部分就不得不熟悉。这部分代码放在CControlUI函数中,源码如下所示:
bool CControlUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
{
// 绘制循序:背景颜色->背景图->状态图->文本->边框
SIZE cxyBorderRound;
RECT rcBorderSize;
if (m_pManager) {
cxyBorderRound = GetManager()->GetDPIObj()->Scale(m_cxyBorderRound);
rcBorderSize = GetManager()->GetDPIObj()->Scale(m_rcBorderSize);
}
else {
cxyBorderRound = m_cxyBorderRound;
rcBorderSize = m_rcBorderSize;
}
if( cxyBorderRound.cx > 0 || cxyBorderRound.cy > 0 ) {
CRenderClip roundClip;
CRenderClip::GenerateRoundClip(hDC, m_rcPaint, m_rcItem, cxyBorderRound.cx, cxyBorderRound.cy, roundClip);
PaintBkColor(hDC);
PaintBkImage(hDC);
PaintStatusImage(hDC);
PaintForeColor(hDC);
PaintForeImage(hDC);
PaintText(hDC);
PaintBorder(hDC);
}
else {
PaintBkColor(hDC);
PaintBkImage(hDC);
PaintStatusImage(hDC);
PaintForeColor(hDC);
PaintForeImage(hDC);
PaintText(hDC);
PaintBorder(hDC);
}
return true;
}
以上代码比较清晰,就是按照背景颜色->背景图->状态图->文本->边框的顺序绘制,第一个是绘制背景颜色,代码如下所示:
void CControlUI::PaintBkColor(HDC hDC)
{
//支持三重渐变色的绘制
if( m_dwBackColor != 0 ) {
bool bVer = (m_sGradient.CompareNoCase(_T("hor")) != 0);
if( m_dwBackColor2 != 0 ) {
if( m_dwBackColor3 != 0 ) {
RECT rc = m_rcItem;
rc.bottom = (rc.bottom + rc.top) / 2;
CRenderEngine::DrawGradient(hDC, rc, GetAdjustColor(m_dwBackColor), GetAdjustColor(m_dwBackColor2), bVer, 8);
rc.top = rc.bottom;
rc.bottom = m_rcItem.bottom;
CRenderEngine::DrawGradient(hDC, rc, GetAdjustColor(m_dwBackColor2), GetAdjustColor(m_dwBackColor3), bVer, 8);
}
else {
CRenderEngine::DrawGradient(hDC, m_rcItem, GetAdjustColor(m_dwBackColor), GetAdjustColor(m_dwBackColor2), bVer, 16);
}
}
else if( m_dwBackColor >= 0xFF000000 ) CRenderEngine::DrawColor(hDC, m_rcPaint, GetAdjustColor(m_dwBackColor));
else CRenderEngine::DrawColor(hDC, m_rcItem, GetAdjustColor(m_dwBackColor));
}
}
第二步是绘制背景图,代码如下所示:
void CControlUI::PaintBkImage(HDC hDC)
{
if( m_sBkImage.IsEmpty() ) return;
if( !DrawImage(hDC, (LPCTSTR)m_sBkImage) ) {}
}
第三步是绘制状态图,根控件,该函数是空的,在一些动态控件中,该函数是有的,代码如下所示:
void CControlUI::PaintStatusImage(HDC hDC)
{
return;
}
第四步是绘制前景色,代码如下所示:
void CControlUI::PaintForeColor(HDC hDC)
{
CRenderEngine::DrawColor(hDC, m_rcItem, GetAdjustColor(m_dwForeColor));
}
第五步是绘制前景图像,代码如下所示:
void CControlUI::PaintForeImage(HDC hDC)
{
if( m_sForeImage.IsEmpty() ) return;
DrawImage(hDC, (LPCTSTR)m_sForeImage);
}
第六步是绘制文本,代码如下所示:
void CControlUI::PaintText(HDC hDC)
{
return;
}
最后一步是绘制边框,代码如下所示:
void CControlUI::PaintBorder(HDC hDC)
{
int nBorderSize;
SIZE cxyBorderRound;
RECT rcBorderSize;
if (m_pManager) {
nBorderSize = GetManager()->GetDPIObj()->Scale(m_nBorderSize);
cxyBorderRound = GetManager()->GetDPIObj()->Scale(m_cxyBorderRound);
rcBorderSize = GetManager()->GetDPIObj()->Scale(m_rcBorderSize);
}
else {
nBorderSize = m_nBorderSize;
cxyBorderRound = m_cxyBorderRound;
rcBorderSize = m_rcBorderSize;
}
if(m_dwBorderColor != 0 || m_dwFocusBorderColor != 0) {
//画圆角边框
if(nBorderSize > 0 && ( cxyBorderRound.cx > 0 || cxyBorderRound.cy > 0 )) {
if (IsFocused() && m_dwFocusBorderColor != 0)
CRenderEngine::DrawRoundRect(hDC, m_rcItem, nBorderSize, cxyBorderRound.cx, cxyBorderRound.cy, GetAdjustColor(m_dwFocusBorderColor), m_nBorderStyle);
else
CRenderEngine::DrawRoundRect(hDC, m_rcItem, nBorderSize, cxyBorderRound.cx, cxyBorderRound.cy, GetAdjustColor(m_dwBorderColor), m_nBorderStyle);
}
else {
if (IsFocused() && m_dwFocusBorderColor != 0 && nBorderSize > 0) {
CRenderEngine::DrawRect(hDC, m_rcItem, nBorderSize, GetAdjustColor(m_dwFocusBorderColor), m_nBorderStyle);
}
else if(rcBorderSize.left > 0 || rcBorderSize.top > 0 || rcBorderSize.right > 0 || rcBorderSize.bottom > 0) {
RECT rcBorder;
if(rcBorderSize.left > 0){
rcBorder = m_rcItem;
rcBorder.right = rcBorder.left;
CRenderEngine::DrawLine(hDC,rcBorder,rcBorderSize.left,GetAdjustColor(m_dwBorderColor),m_nBorderStyle);
}
if(rcBorderSize.top > 0){
rcBorder = m_rcItem;
rcBorder.bottom = rcBorder.top;
CRenderEngine::DrawLine(hDC,rcBorder,rcBorderSize.top,GetAdjustColor(m_dwBorderColor),m_nBorderStyle);
}
if(rcBorderSize.right > 0){
rcBorder = m_rcItem;
rcBorder.right -= 1;
rcBorder.left = rcBorder.right;
CRenderEngine::DrawLine(hDC,rcBorder,rcBorderSize.right,GetAdjustColor(m_dwBorderColor),m_nBorderStyle);
}
if(rcBorderSize.bottom > 0){
rcBorder = m_rcItem;
rcBorder.bottom -= 1;
rcBorder.top = rcBorder.bottom;
CRenderEngine::DrawLine(hDC,rcBorder,rcBorderSize.bottom,GetAdjustColor(m_dwBorderColor),m_nBorderStyle);
}
}
else if(nBorderSize > 0) {
CRenderEngine::DrawRect(hDC, m_rcItem, nBorderSize, GetAdjustColor(m_dwBorderColor), m_nBorderStyle);
}
}
}
}
绘制圆角矩形或者普通矩形,或者可控制矩形的四条边的绘制。以上绘制步骤在头文件里都申明为虚函数,继承至该控件的新控件可以修改部分,从而实现新控件的功能,头文件的代码如下:
virtual bool Paint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl = NULL); // 返回要不要继续绘制
virtual bool DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl);
virtual void PaintBkColor(HDC hDC);
virtual void PaintBkImage(HDC hDC);
virtual void PaintStatusImage(HDC hDC);
virtual void PaintForeColor(HDC hDC);
virtual void PaintForeImage(HDC hDC);
virtual void PaintText(HDC hDC);
virtual void PaintBorder(HDC hDC);
【小节】从以上的源代码分析,duilib的绘制功能并不强大,只是实现了文本,图像和边框的简单绘制,那为什么duilib又能制作那么绚丽的界面效果,原因在于强大的贴图功能,就是将效果制作成图片,然后绘制到控件上,而不需要从代码上实现。
欢迎光临知了软件开发网络平台,本公司定制开发各类软件,主要方向为桌面专业软件开发和插件定制开发,桌面软件主要包括文字图形识别类软件,信息管理类软件,3D打印类软件,视频类软件以及其它涉及专业的各类图形图像处理软件。插件包含AE插件,AI插件,PS插件,PDF插件,3DMAX插件以及Word,Excel等Office插件开发。详情请咨询,微信QQ:312117271,手机:18928899728,邮箱: anjingzhi_sea@163.com.
公司网址:http://www.zhiliaos.com
本文地址:https://blog.csdn.net/weixin_42247427/article/details/107296874
上一篇: MD和RD命令的使用方法