duilib-自定义曲线控件
duilib现有的控件继承图如下:
从上图可以看出常见的控件都是由CControlUI继承而来,因此如果需要自定义控件,可以继承CControlUI,重写子类。如何做一个类似windows任务管理器的曲线控件,如下图所示:
自定义曲线控件展示如下:
下面详细说明如何在duilib源码中自定义曲线控件,以及如何在xml中设置控件属性。
1、重写控件类CChartCtrlUI,继承于CLabelUI或者CControlUI,控件类CChartCtrlUI中必须重写的函数方法如下:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
void DoEvent(TEventUI& event);
void DoPaint(HDC hDC, const RECT& rcPaint);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
GetClass()返回自定义的控件name属性值
LPCTSTR CChartCtrlUI::GetClass() const
{
return DUI_CTR_CHART_CONTROL;
}
GetInterface()返回控件指针
LPVOID CChartCtrlUI::GetInterface(LPCTSTR pstrName)
{
if (_tcscmp(pstrName, DUI_CTR_CHART_CONTROL) == 0) return static_cast<CChartCtrlUI*>(this);
return CControlUI::GetInterface(pstrName);
}
DoEvent()重写控件响应,包括鼠标键盘的动作,触发后发送UI主线程通知消息,如果需要捕获消息请重写DoEvent.
void CChartCtrlUI::DoEvent(TEventUI& event)
{
CControlUI::DoEvent(event);
}
DoPaint()控件界面重绘,可以在此函数内绘制图像,曲线等等,如何使用gdi+绘制曲线,画图等,可以参考网上资料。
void CChartCtrlUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
CControlUI::DoPaint(hDC, rcPaint);
m_rectChart = this->GetPos();
//重绘制曲线图
{
Pen pen(m_curvPenColor);
Graphics graphics(hDC);
graphics.SetSmoothingMode(SmoothingModeAntiAlias);
Status restatus = graphics.DrawCurve(&pen, (const PointF*)m_stPointXy, m_nCurPointCount);
m_bDataAdd = false;
}
}
SetAttribute()解析界面xml文件中控件自定义属性值,如何解析可以参考CLabelUI或CControlUI类中的SetAttribute函数,例如自定义了curvpen,曲线画笔颜色,截取控件宽度值,设置曲线绘制点数总和,方便平移操作。
void CChartCtrlUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
LPTSTR pstr = NULL;
if (_tcscmp(pstrName, _T("curvpen")) == 0) {
if (*pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetCurvPenColor(clrColor);
}
else if (_tcscmp(pstrName, _T("width")) == 0)
{
DWORD dwWidth = _tcstoul(pstrValue, &pstr, 10);
int nWidth;
nWidth = dwWidth;
ASSERT(nWidth > 0);
m_stPointXy = new PointF[nWidth];
ASSERT(m_stPointXy != NULL);
CControlUI::SetAttribute(pstrName, pstrValue);
}
else
CControlUI::SetAttribute(pstrName, pstrValue);
}
2、在UIDefine.h中添加控件类名的宏定义。
#define DUI_CTR_CHART_CONTROL (_T("ChartControl"))
3、在UIDlgBuilder.cpp的_paser函数中增加控件的创建代码,根据类名的长度为12,写在case 12下:
case 12:
if (_tcscmp(pstrClass, DUI_CTR_CHART_CONTROL) == 0) pControl = new CChartCtrlUI;
break;
4、在UIlib.h中包含头文件
#include "Control/UIChartCtrl.h"
5、使用xml编写
<ChartControl name="cpuChart" text=" " textcolor="#FFFF0000" height="40" width="160" bordersize="1" bordercolor="#FF1E90FF" curvpen="#FF1E90FF" />
6、头文件与源文件如下
//UIChartCtrl.h
#ifndef UI_CHART_CTRL_H
#define UI_CHART_CTRL_H
#pragma once
#include <GdiPlus.h>
#pragma comment( lib, "GdiPlus.lib" )
using namespace Gdiplus;
class UILIB_API Gdiplus::RectF;
struct UILIB_API Gdiplus::GdiplusStartupInput;
namespace DuiLib
{
class UILIB_API CChartCtrlUI : public CLabelUI
{
public:
CChartCtrlUI();
~CChartCtrlUI();
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
void SetEnabledEffect(bool _EnabledEffect);
bool GetEnabledEffect();
void SetText(LPCTSTR pstrText);
CDuiString GetText() const;
void DoEvent(TEventUI& event);
void DoPaint(HDC hDC, const RECT& rcPaint);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
void SetCurvPenColor(DWORD dwColor);
void InitCtrl(); //初始化数据,分配数据空间
int GetPointCount();
void AddPointXy(PointF clsPointF);
PointF valueToPointF(float value);
private:
DWORD m_curvPenColor; //绘制曲线画笔
PointF * m_stPointXy;//显示100个值,超过就后移
int m_nCurPointCount;
bool m_EnableEffect;
CDuiString m_TextValue;
ULONG_PTR m_gdiplusToken;
GdiplusStartupInput m_gdiplusStartupInput;
bool m_bDataAdd; //是否有数据加入,加入则重绘
bool m_bFirstUpdate; //是否界面更新一次
RECT m_rectChart; //窗口相对于客户区的坐标
};
}
#endif
//UIChartCtrl.cpp
#include "StdAfx.h"
#include "UIChartCtrl.h"
#include <atlconv.h>
namespace DuiLib
{
CChartCtrlUI::CChartCtrlUI() : m_gdiplusToken(0),
m_EnableEffect(false),
m_stPointXy(NULL),
m_bDataAdd(false),
m_bFirstUpdate(false)
{
m_nCurPointCount = 0;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
}
CChartCtrlUI::~CChartCtrlUI()
{
try
{
GdiplusShutdown(m_gdiplusToken);
if (m_stPointXy != NULL)
{
delete m_stPointXy;
m_stPointXy = NULL;
}
}
catch (...)
{
throw "CChartCtrlUI::~CChartCtrlUI";
}
}
LPCTSTR CChartCtrlUI::GetClass() const
{
return DUI_CTR_CHART_CONTROL;
}
LPVOID CChartCtrlUI::GetInterface(LPCTSTR pstrName)
{
if (_tcscmp(pstrName, DUI_CTR_CHART_CONTROL) == 0) return static_cast<CChartCtrlUI*>(this);
return CControlUI::GetInterface(pstrName);
}
CDuiString CChartCtrlUI::GetText() const
{
try
{
if (!m_EnableEffect)
return CControlUI::GetText();
return m_TextValue;
}
catch (...)
{
throw "CChartCtrlUI::GetText";
}
}
void CChartCtrlUI::SetText(LPCTSTR pstrText)
{
try
{
if (!GetEnabledEffect())
return CControlUI::SetText(pstrText);
m_TextValue = pstrText;
}
catch (...)
{
throw "CChartCtrlUI::SetText";
}
}
void CChartCtrlUI::SetEnabledEffect(bool _EnabledEffect)
{
try
{
m_EnableEffect = _EnabledEffect;
}
catch (...)
{
throw "CLabelUI::SetEnabledEffect";
}
}
bool CChartCtrlUI::GetEnabledEffect()
{
try
{
return m_EnableEffect;
}
catch (...)
{
throw "CLabelUI::GetEnabledEffect";
}
}
void CChartCtrlUI::DoEvent(TEventUI& event)
{
CControlUI::DoEvent(event);
}
void CChartCtrlUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
LPTSTR pstr = NULL;
if (_tcscmp(pstrName, _T("curvpen")) == 0) {
if (*pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetCurvPenColor(clrColor);
}
else if (_tcscmp(pstrName, _T("width")) == 0)
{
DWORD dwWidth = _tcstoul(pstrValue, &pstr, 10);
int nWidth;
nWidth = dwWidth;
ASSERT(nWidth > 0);
m_stPointXy = new PointF[nWidth];
ASSERT(m_stPointXy != NULL);
CControlUI::SetAttribute(pstrName, pstrValue);
}
else
CControlUI::SetAttribute(pstrName, pstrValue);
}
void CChartCtrlUI::SetCurvPenColor(DWORD dwColor)
{
m_curvPenColor = dwColor;
}
int CChartCtrlUI::GetPointCount()
{
return m_nCurPointCount;
}
void CChartCtrlUI::InitCtrl()
{
//int width = this->GetWidth();
//ASSERT(width > 0);
//m_stPointXy = new PointF[width];
//ASSERT(m_stPointXy != NULL);
int width;
m_rectChart = this->GetPos();
width = m_rectChart.right - m_rectChart.left;
ASSERT(width > 0);
m_stPointXy = new PointF[width];
ASSERT(m_stPointXy != NULL);
}
void CChartCtrlUI::AddPointXy(PointF clsPointF)
{
POINTF tempPf;
if (m_nCurPointCount > this->GetWidth())
return;
if (m_nCurPointCount == this->GetWidth())
{
for (int i = 0; i < m_nCurPointCount-1; i++)
{
m_stPointXy[i].Y = m_stPointXy[i+1].Y;
//X值保持不变
}
m_stPointXy[m_nCurPointCount-1] = clsPointF;
}
else
{
m_stPointXy[m_nCurPointCount].X = clsPointF.X;
m_stPointXy[m_nCurPointCount].Y = clsPointF.Y;
m_nCurPointCount++;
}
m_bDataAdd = true;
}
PointF CChartCtrlUI::valueToPointF(float value)
{
PointF clsRes;
int height, width;
height = this->GetHeight();
width = this->GetWidth();
ASSERT(height > 0);
ASSERT(width > 0);
clsRes.Y = m_rectChart.top + (height - value / 100.0 * height);
if (m_nCurPointCount < width)
clsRes.X = m_nCurPointCount + 1 + m_rectChart.left;
else
clsRes.X = m_nCurPointCount + m_rectChart.left;
return clsRes;
}
void CChartCtrlUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
CControlUI::DoPaint(hDC, rcPaint);
m_rectChart = this->GetPos();
//重绘制曲线图
//if (m_bDataAdd) //有数据加入
{
Pen pen(m_curvPenColor);
Graphics graphics(hDC);
graphics.SetSmoothingMode(SmoothingModeAntiAlias);
Status restatus = graphics.DrawCurve(&pen, (const PointF*)m_stPointXy, m_nCurPointCount);
m_bDataAdd = false;
}
}
}