先看效果图

实现过程
1、要在Duilib中实现自定义绘图,需要继承一个控件,并重写它的DoPaint
函数,这里我们继承CControlUI实现一个绘图的类CPaintUI:
class CPaintUI:public CControlUI
{
public:
CPaintUI();
~CPaintUI();
LPCTSTR GetClass() const override;
LPVOID GetInterface(LPCTSTR pstrName) override;
void Init() override;
void DoEvent(TEventUI& event) override;
bool DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl) override;
void DrawMarqueeText(HDC hDC);
int g_nControlWidth; //基础宽度
int m_nStep; //移动距离
int m_nHeight; //绘图高度
int m_nTimer; //时间间隔
int m_nLeft; //第一段话的位置
int m_nRight//第二段话的位置
CDuiString m_szText; //显示的文本
Gdiplus::SolidBrush* solidbrush; // 蓝色画刷
Gdiplus::Font* gdifont; // 字体
Gdiplus::StringFormat sf;
};
2、在CPP中实现各个函数:
CPaintUI::CPaintUI()
{
DUITRACE(L"CPaintUI");
m_nStep = 2;
m_nHeight = 30;
m_nTimer = 20;
m_szText = _T("这是一段文本...");
g_nControlWidth = 800;//根据界面宽度自定义
m_nLeft = 0;
m_nRight = g_nControlWidth ;
solidbrush = new SolidBrush(Color(0xFF, 0, 159, 0)); // 蓝色画刷
gdifont = new Gdiplus::Font(L"微软雅黑", 20, FontStyleRegular, UnitPixel);
sf.SetAlignment(StringAlignmentNear); // 单行靠左
sf.SetLineAlignment(StringAlignmentCenter); // 文本垂直居中显示
}
CPaintUI::~CPaintUI()
{
}
LPCTSTR CPaintUI::GetClass() const
{
return L"PaintUI";
}
LPVOID CPaintUI::GetInterface(LPCTSTR pstrName)
{
if (_tcsicmp(pstrName, _T("Paint")) == 0)
return this;
return __super::GetInterface(pstrName);
}
void CPaintUI::Init()
{
__super::Init();
//设置定时器
m_pManager->SetTimer(this, 1, m_nTimer);
}
void CPaintUI::DoEvent(TEventUI& event)
{
if (event.Type == UIEVENT_TIMER)
{
this->Invalidate();//定时刷新界面显示
}
return CControlUI::DoEvent(event);
}
//绘图
bool CPaintUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
{
PaintBkColor(hDC);//绘制背景,默认背景
DrawMarqueeText(hDC);//绘制MarqueeText
return true;
}
3、绘制MarqueeText
void CPaintUI::DrawMarqueeText(HDC hDC)
{
Gdiplus::Graphics graphics(hDC);
CDuiRect rect = GetPos();//绘图区域大小
Gdiplus::RectF gdiRc(m_nLeft, clientRect.top + m_nHeight, clientRect.GetWidth(), m_nHeight);//绘制文本区域
RectF boundRect;
graphics.MeasureString(m_szText, wcslen(m_szText), gdifont, gdiRc, &sf, &boundRect);//文本长度
graphics.DrawString(m_szText, wcslen(m_szText), gdifont, gdiRc, &sf, solidbrush);//绘制第一条文本
m_nLeft -= m_nStep; // 从右到左递进
if (m_gRestart)//开始绘制第二条文本
{
m_nRight -= m_nStep; // 从右到左递进
Gdiplus::RectF secRc(m_nRight, clientRect.top + m_nHeight, clientRect.GetWidth(), m_nHeight);//第二条文本区域
graphics.DrawString(m_szText, wcslen(m_szText), gdifont, secRc, &sf, solidbrush);
if (m_nRight <= -boundRect.Width)//当第二条完全消失在左边时,停止绘制
{
m_gRestart = FALSE;
}
if (m_nRight <= 0)//当第二条开始逐渐消失时,绘制第一条
{
if (!m_bEnd)
{
m_nLeft = rect.GetWidth();
m_bEnd = TRUE;
}
}
}
if (m_nLeft <= 0) // 第一个字符串已经前进一部分,准备显示第二个字符串
{
if (!m_gRestart)
{
m_nRight = rect.GetWidth();
m_gRestart = TRUE;
m_bEnd = FALSE;
}
}
}
4、这样就得到了一行不断进行的跑马灯效果,如果想实现上图那样的效果,只需要多定义几行数据,随机初始化位置和文本即可。
网友评论