侵权删,未经允许禁止转载!
前言:
刚上手duilib,还不太熟悉,而且没有官方文档,所以写几个实战项目来学习并巩固一下。
使用或实现的部分技术细节:
**1、**主窗体的边框
**2、**默认字体,控件默认属性的标签定义
**3、**CTextUI控件的简配html功能,包括a、c标签的使用(其中当align处于center时,点击超链接有bug)
**4、**使用到的控件标签主要有Button,Text,Control,RichEdit,Edit,CheckBox,ComboBox等
**5、**实现自定义控件(此项目中使用自定义控件的原因是因为CControlUI并没有将鼠标进入和离开事件转化为Notify,所以只能自己继承并重写标签,实现对这两个事件的控制)
**6、**通过定时器实现动画效果(在duilib中暂时没找到类似ProcessMessage这样的方法,所以暂时通过定时器来实现相关的功能)
**7、**模态窗的使用
效果展示:
核心代码如下:
test.xml
networkset.xml
main.cpp
// test1.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "duiTest.h"
#include
#include
using namespace DuiLib;
#define TIMER_QR_MOVE 1001
#define TIMER_QR_RESTORE 1002
#define TIMER_INVALIDATE 1003
#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
//重写一个可以响应mouseenter和mousemove的control控件
class CMoveControlUI :public CControlUI
{
public:
virtual void DoEvent(TEventUI&event)
{
if (event.Type == UIEVENT_MOUSEENTER)
{
m_pManager->SendNotify(this, DUI_MSGTYPE_MOUSEENTER, event.wParam, event.lParam);
return;
}
if (event.Type == UIEVENT_MOUSELEAVE)
{
m_pManager->SendNotify(this, DUI_MSGTYPE_MOUSELEAVE, event.wParam, event.lParam);
return;
}
if (m_pParent != NULL) m_pParent->DoEvent(event);
}
LPVOID GetInterface(LPCTSTR pstrName)
{
if (_tcscmp(pstrName, _T("MoveControl")) == 0) return static_cast(this);
return CControlUI::GetInterface(pstrName);
}
LPCTSTR GetClass() const
{
return _T("MoveControl");
}
};
class CSetFrameWnd : public WindowImplBase
{
public:
virtual LPCTSTR GetWindowClassName() const { return _T("NetworkSet"); }
virtual CDuiString GetSkinFile() { return _T("networkset.xml"); }
virtual CDuiString GetSkinFolder() { return _T("skin"); }
virtual void Notify(TNotifyUI& msg) override
{
__super::Notify(msg);
}
};
class CMainFrameWnd : public WindowImplBase
{
public:
virtual LPCTSTR GetWindowClassName() const { return _T("DUIMainFrame"); }
virtual CDuiString GetSkinFile() { return _T("test.xml"); }
virtual CDuiString GetSkinFolder() { return _T("skin"); }
virtual CControlUI* CreateControl(LPCTSTR pstrClass) override
{
//创建自定义控件
if (0 == _tcsicmp(pstrClass, _T("MoveControl")))
{
return new CMoveControlUI;
}
return __super::CreateControl(pstrClass);
}
//初始化
virtual void InitWindow() override
{
//刷新一次窗口,猜测richedit在绘制背景图片后有个bug??初次点击输入账号会自动focus到输入密码的richedit
::SetTimer(GetHWND(), TIMER_INVALIDATE, 800, NULL);
}
virtual void Notify(TNotifyUI& msg)
{
if (msg.sType == DUI_MSGTYPE_CLICK)
{
if (msg.pSender->GetName() == _T("setbtn"))
{
//弹出设置窗口!
CSetFrameWnd setFrameWnd;
//第一个参数为NULL时为非模态窗,否则为模态窗
setFrameWnd.Create(this->GetHWND(), _T("SetFrameWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
setFrameWnd.CenterWindow();
setFrameWnd.ShowModal();
}
else if (msg.pSender->GetName() == _T("ImageQR"))
{
}
else if (msg.pSender->GetName() == _T("chkAutoLogin"))
{
//勾选自动登录
CCheckBoxUI* pAutoLogin = static_cast(msg.pSender);
//此时虽然点击了勾选,但实际上控件还处于未勾选状态
if (pAutoLogin && !pAutoLogin->GetCheck())
{
//自动勾选记住密码
CCheckBoxUI* pRememberPass = static_cast(m_PaintManager.FindControl(_T("chkRememberPass")));
if (pRememberPass && !pRememberPass->GetCheck())
{
pRememberPass->SetCheck(true, false);
}
}
}
else if (msg.pSender->GetName() == _T("chkRememberPass"))
{
//取消勾选记住密码时,自动取消自动登录选项
CCheckBoxUI* pRememberPass = static_cast(msg.pSender);
if (pRememberPass && pRememberPass->GetCheck())
{
//取消自动登录选项
CCheckBoxUI* pAutoLogin = static_cast(m_PaintManager.FindControl(_T("chkAutoLogin")));
if (pAutoLogin && pAutoLogin->GetCheck())
{
pAutoLogin->SetCheck(false, false);
}
}
}
}
else if (msg.sType == DUI_MSGTYPE_LINK)
{
if (msg.pSender->GetName() == _T("LinkUseMsgLogin") || msg.pSender->GetName() == _T("LinkUsePasswordLogin"))
{
bool bUseMsgLogin = (msg.pSender->GetName() == _T("LinkUseMsgLogin"));
//隐藏账号密码登录,并显示手机验证码登录
CVerticalLayoutUI*pMsgLogin = static_cast(this->m_PaintManager.FindControl(_T("MsgLogin")));
if (pMsgLogin)
pMsgLogin->SetVisible(bUseMsgLogin);
CVerticalLayoutUI*pPasswordLogin = static_cast(this->m_PaintManager.FindControl(_T("PasswordLogin")));
if (pPasswordLogin)
pPasswordLogin->SetVisible(!bUseMsgLogin);
CHorizontalLayoutUI* pBDProtocol = static_cast(this->m_PaintManager.FindControl(_T("BDProtocolLayout")));
if (pBDProtocol)
pBDProtocol->SetVisible(bUseMsgLogin);
}
else if (msg.pSender->GetName() == _T("linkOpenApp") ||
msg.pSender->GetName() == _T("linkForgetPass") ||
msg.pSender->GetName() == _T("linkRegistry") ||
msg.pSender->GetName() == _T("BDProtocol"))
{
//打开超链接
CTextUI *pLinkOpenApp = static_cast(msg.pSender);
if (pLinkOpenApp)
{
//用默认浏览器打开网页
::ShellExecute(NULL, _T("open"), pLinkOpenApp->GetLinkContent(0)->GetData(), NULL, NULL, SW_SHOW);
}
}
}
else if (msg.sType == DUI_MSGTYPE_MOUSEENTER)
{
//移动图片
if (msg.pSender->GetName() == _T("ImageQR") || msg.pSender->GetName() == _T("ImageHelp"))
{
::KillTimer(GetHWND(), TIMER_QR_MOVE);
::KillTimer(GetHWND(), TIMER_QR_RESTORE);
::SetTimer(GetHWND(), TIMER_QR_MOVE, 10, NULL);
}
}
else if (msg.sType == DUI_MSGTYPE_MOUSELEAVE)
{
//复原图片
if (msg.pSender->GetName() == _T("ImageQR") || msg.pSender->GetName() == _T("ImageHelp"))
{
::KillTimer(GetHWND(), TIMER_QR_MOVE);
::KillTimer(GetHWND(), TIMER_QR_RESTORE);
::SetTimer(GetHWND(), TIMER_QR_RESTORE, 10, NULL);
}
}
else if (msg.sType == DUI_MSGTYPE_KILLFOCUS)
{
//richedit失去焦点
if (msg.pSender->GetName() == _T("edtPhone"))
{
//如果此时没有数据,则显示placeholder
CRichEditUI *pEdtPhone = static_cast(msg.pSender);
if (pEdtPhone && pEdtPhone->GetText().IsEmpty())
{
pEdtPhone->SetBkImage(_T("file='edt_phone_placeholder.jpg' dest='0,4,140,34'"));
}
}
else if (msg.pSender->GetName() == _T("edtCode"))
{
CRichEditUI *pEdtCode = static_cast(msg.pSender);
if (pEdtCode && pEdtCode->GetText().IsEmpty())
{
pEdtCode->SetBkImage(_T("file='edt_msg_placeholder.jpg' dest='0,4,140,34'"));
}
}
else if (msg.pSender->GetName() == _T("edtUsername"))
{
CRichEditUI *pEdtUsername = static_cast(msg.pSender);
if (pEdtUsername && pEdtUsername->GetText().IsEmpty())
{
pEdtUsername->SetBkImage(_T("file='edt_user_placeholder.jpg' dest='0,7,140,37'"));
pEdtUsername->Invalidate();
}
}
else if (msg.pSender->GetName() == _T("edtPassword"))
{
CRichEditUI *pEdtPassword = static_cast(msg.pSender);
if (pEdtPassword && pEdtPassword->GetText().IsEmpty())
{
pEdtPassword->SetBkImage(_T("file='edt_pass_placeholder.jpg' dest='0,7,140,37'"));
pEdtPassword->Invalidate();
}
}
}
else if (msg.sType == DUI_MSGTYPE_SETFOCUS)
{
//richedit获得焦点
if (msg.pSender->GetName() == _T("edtPhone"))
{
//如果没有数据,则清除placeholder背景图片
CRichEditUI *pEdtPhone = static_cast(msg.pSender);
if (pEdtPhone && pEdtPhone->GetText().IsEmpty())
{
pEdtPhone->SetBkImage(_T("file='edt_phone.jpg' dest='0,7,30,37'"));
}
}
else if (msg.pSender->GetName() == _T("edtCode"))
{
CRichEditUI *pEdtCode = static_cast(msg.pSender);
if (pEdtCode && pEdtCode->GetText().IsEmpty())
{
pEdtCode->SetBkImage(_T("file='edt_msg.jpg' dest='0,7,30,37'"));
}
}
else if (msg.pSender->GetName() == _T("edtUsername"))
{
CRichEditUI *pEdtUsername = static_cast(msg.pSender);
if (pEdtUsername && pEdtUsername->GetText().IsEmpty())
{
pEdtUsername->SetBkImage(_T("file='edt_user.png' dest='0,7,30,37'"));
pEdtUsername->Invalidate();
}
}
else if (msg.pSender->GetName() == _T("edtPassword"))
{
CRichEditUI *pEdtPassword = static_cast(msg.pSender);
if (pEdtPassword && pEdtPassword->GetText().IsEmpty())
{
pEdtPassword->SetBkImage(_T("file='edt_pass.png' dest='0,7,30,37'"));
pEdtPassword->Invalidate();
}
}
}
//基类中处理了一些默认按钮的点击事件,子类不处理的就给转到基类
__super::Notify(msg);
}
//通过定时器来实现动画效果
virtual LRESULT HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) override
{
//
switch (uMsg)
{
case WM_TIMER:
if (wParam == TIMER_QR_MOVE || wParam == TIMER_QR_RESTORE)
{
static int nMove = 0;
if (wParam == TIMER_QR_MOVE)
{
//移动
CMoveControlUI *pImageQR = static_cast(m_PaintManager.FindControl(_T("ImageQR")));
if (pImageQR)
{
if (nMove > 10)
{
//显示帮助图片
CMoveControlUI* pImageHelp = static_cast(m_PaintManager.FindControl(_T("ImageHelp")));
if (pImageHelp)
{
pImageHelp->SetBkImage(_T("scan_help.jpg"));
//开启mouse事件,事件响应同ImageQR控件
pImageHelp->SetMouseEnabled(true);
}
::KillTimer(GetHWND(), TIMER_QR_MOVE);
return 0;
}
++nMove;
SIZE moveSize;
moveSize.cx = -5;
moveSize.cy = 0;
pImageQR->Move(moveSize);
m_PaintManager.Invalidate();
}
}
else if (wParam == TIMER_QR_RESTORE)
{
//恢复
CMoveControlUI *pImageQR = static_cast(m_PaintManager.FindControl(_T("ImageQR")));
if (pImageQR)
{
CMoveControlUI* pImageHelp = static_cast(m_PaintManager.FindControl(_T("ImageHelp")));
if (pImageHelp && _wcsicmp(pImageHelp->GetBkImage(), _T("scan_help.jpg")) == 0)
{
pImageHelp->SetBkImage(_T(""));
}
if (nMove <= 0)
{
//关闭mouse事件
pImageHelp->SetMouseEnabled(false);
::KillTimer(GetHWND(), TIMER_QR_RESTORE);
return 0;
}
--nMove;
SIZE moveSize;
moveSize.cx = 5;
moveSize.cy = 0;
pImageQR->Move(moveSize);
m_PaintManager.Invalidate();
}
}
}
else if (wParam == TIMER_INVALIDATE)
{
::KillTimer(GetHWND(), TIMER_INVALIDATE);
m_PaintManager.Invalidate();
}
break;
default:
break;
}
return WindowImplBase::HandleCustomMessage(uMsg, wParam, lParam, bHandled);
}
};
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
CPaintManagerUI::SetInstance(hInstance);
CMainFrameWnd mainFrame;
mainFrame.Create(NULL, _T("MainWindow"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
mainFrame.CenterWindow();
mainFrame.ShowModal();
return 0;
}