https://blog.csdn.net/c_base_jin/article/details/80472937
圆形进度条在duilib框架中是非基础控件,我们需要基于Progress控件进行自绘制,核心代码包括UICircleProgress.h和UICircleProgress.cpp两个文件,其代码如下:
UICircleProgress.h
#ifndef __UICIRCLE_PROGRESS_H__
#define __UICIRCLE_PROGRESS_H__
#pragma once
namespace DuiLib
{
class CCircleProgressUI :
public CProgressUI
{
public:
CCircleProgressUI(void);
~CCircleProgressUI(void);
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
void SetCircular(BOOL bCircular = TRUE);
void SetClockwiseRotation(BOOL bClockwise = TRUE);
void SetCircleWidth(DWORD dwCircleWidth);
void SetBgColor(DWORD dwBgColor);
DWORD GetBgColor() const;
void SetFgColor(DWORD dwBgColor);
DWORD GetFgColor() const;
void SetIndicator(LPCTSTR lpIndicatorImage);
void SetEnableCircleEffect(BOOL bEnableCircleEffect = FALSE);
void SetCircleGradientColor1(DWORD dwColor);
void SetCircleGradientColor2(DWORD dwColor);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
void PaintBkColor(HDC hDC);
private:
BOOL m_bCircular;
BOOL m_bClockwise;
DWORD m_dwCircleWidth;
DWORD m_dwBgColor;
DWORD m_dwFgColor;
BOOL m_bEnableCircleEffect;
DWORD m_dwGradientColor1;
DWORD m_dwGradientColor2;
Image* m_pIndicator;
CDuiString m_sIndicatorImage;
};
} //namespace Duilib
#endif // !CIRCLE_PROGRESS_H
UICircleProgress.cpp
#include "stdafx.h"
#include "UICircleProgress.h"
namespace DuiLib
{
extern int GetEncoderClsid(const WCHAR* format, CLSID *pClsid);
extern Color ARGB2Color(DWORD dwColor);
CCircleProgressUI::CCircleProgressUI(void)
: m_bCircular(FALSE)
, m_bClockwise(TRUE)
, m_dwCircleWidth(10.0)
, m_dwFgColor()
, m_dwBgColor()
, m_bEnableCircleEffect(FALSE)
, m_dwGradientColor1()
, m_dwGradientColor2()
, m_sIndicatorImage("")
, m_pIndicator(NULL)
{
}
CCircleProgressUI::~CCircleProgressUI(void)
{
if (m_pIndicator)
{
delete m_pIndicator;
}
}
void CCircleProgressUI::SetCircular(BOOL bCircular /* = TRUE */)
{
m_bCircular = bCircular;
Invalidate();
}
void CCircleProgressUI::SetClockwiseRotation(BOOL bClockwise)
{
if (bClockwise != m_bClockwise)
{
m_bClockwise = bClockwise;
if (m_pIndicator)
{
//已经旋转了图片,旋转到相反的方向
m_pIndicator->RotateFlip(Rotate180FlipNone);
}
}
}
void CCircleProgressUI::SetCircleWidth(DWORD dwCircleWidth)
{
m_dwCircleWidth = dwCircleWidth;
Invalidate();
}
void CCircleProgressUI::SetBgColor(DWORD dwBgColor)
{
m_dwBgColor = dwBgColor;
Invalidate();
}
DWORD CCircleProgressUI::GetBgColor() const
{
return m_dwBgColor;
}
void CCircleProgressUI::SetFgColor(DWORD dwFgColor)
{
m_dwFgColor = dwFgColor;
Invalidate();
}
DWORD CCircleProgressUI::GetFgColor() const
{
return m_dwFgColor;
}
void CCircleProgressUI::SetIndicator(LPCTSTR lpIndicatorImage)
{
ASSERT(lpIndicatorImage);
if (m_sIndicatorImage != lpIndicatorImage)
{
m_sIndicatorImage = lpIndicatorImage;
const TImageInfo* imgInfo = GetManager()->GetImageEx(m_sIndicatorImage);
BITMAP bmp;
GetObject(imgInfo->hBitmap, sizeof(BITMAP), &bmp);
m_pIndicator = new Bitmap(imgInfo->nX, imgInfo->nY, imgInfo->nX * 4, PixelFormat32bppARGB, (BYTE*)bmp.bmBits);
Status state = m_pIndicator->GetLastStatus();
if (Ok == state)
{
// 假定图片指向上
m_pIndicator->RotateFlip(m_bClockwise ? Rotate90FlipNone : Rotate270FlipNone);
Invalidate();
}
}
}
void CCircleProgressUI::SetEnableCircleEffect(BOOL bEnableCircleEffect)
{
m_bEnableCircleEffect = bEnableCircleEffect;
}
void CCircleProgressUI::SetCircleGradientColor1(DWORD dwColor)
{
m_dwGradientColor1 = dwColor;
Invalidate();
}
void CCircleProgressUI::SetCircleGradientColor2(DWORD dwColor)
{
m_dwGradientColor2 = dwColor;
Invalidate();
}
void CCircleProgressUI::PaintBkColor(HDC hDC)
{
CProgressUI::PaintBkColor(hDC);
if (m_bCircular)
{
if (m_nMax <= m_nMin) m_nMax = m_nMin + 1;
if (m_nValue > m_nMax) m_nValue = m_nMax;
if (m_nValue < m_nMin) m_nValue = m_nMin;
int direction = m_bClockwise ? 1 : -1;
Gdiplus::REAL bordersize = 1.0;
Graphics graphics(hDC);
graphics.SetSmoothingMode(SmoothingModeAntiAlias);
// 圆形中心
PointF center;
center.X = m_rcItem.left + (m_rcItem.right - m_rcItem.left) / 2;
center.Y = m_rcItem.top + (m_rcItem.bottom - m_rcItem.top) / 2;
// 控件矩形内的最大正方形的边界
int side = min(m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top);
RectF rcBorder;
rcBorder.X = center.X - side / 2;
rcBorder.Y = center.Y - side / 2;
rcBorder.Width = side;
rcBorder.Height = side;
// 进度弧形的边界
Gdiplus::RectF outer = rcBorder;
if (m_pIndicator)
{
outer.Inflate(-1.0F * m_pIndicator->GetWidth() / 2, -1.0F * m_pIndicator->GetWidth() / 2);
}
else
{
outer.Inflate(-0.5 * m_dwCircleWidth, -0.5 * m_dwCircleWidth);
}
outer.Inflate(-1.0F, -1.0F);
Pen borderPen(Color::White, bordersize);
Pen bgPen(m_dwBgColor, m_dwCircleWidth);
//graphics.DrawEllipse(&borderPen, outer);
RectF rcArk;
rcArk.X = outer.X + outer.Width / 2 - m_dwCircleWidth / 2;
rcArk.Y = outer.Y - m_dwCircleWidth / 2;
rcArk.Width = rcArk.Height = m_dwCircleWidth;
if (!m_bEnableCircleEffect)
{
Pen fgPen(m_dwFgColor, m_dwCircleWidth);
graphics.DrawArc(&bgPen, outer, 270, 360);
graphics.DrawArc(&fgPen, outer, 270, direction * 360 * (m_nValue - m_nMin) / (m_nMax - m_nMin));
}
else
{
REAL factors[4] = { 0.0f, 0.9f, 0.0f };
REAL position[4] = { 0.0f, 0.5f, 1.0f };
LinearGradientBrush lgbrush(rcBorder, ARGB2Color(m_dwGradientColor1), ARGB2Color(m_dwGradientColor2), LinearGradientModeVertical);
lgbrush.SetBlend(factors, position, 3);
//graphics.FillRectangle(&lgbrush, rcBorder);
graphics.DrawArc(&bgPen, outer, 270, 360);
Pen fgPen(&lgbrush, m_dwCircleWidth);
graphics.DrawArc(&fgPen, outer, 270, direction * 360 * (m_nValue - m_nMin) / (m_nMax - m_nMin));
}
Matrix matrix;
matrix.RotateAt(direction * 360 * (m_nValue - m_nMin) / (m_nMax - m_nMin), center, MatrixOrderAppend);
graphics.SetTransform(&matrix);
if (m_pIndicator)
{
RectF rectf;
rectf.X = center.X - m_pIndicator->GetWidth() / 2;
rectf.Y = outer.Y + bordersize / 2 - m_pIndicator->GetHeight() / 2;
rectf.Width = m_pIndicator->GetWidth();
rectf.Height = m_pIndicator->GetHeight();
graphics.DrawImage(m_pIndicator, rectf);
}
}
}
void CCircleProgressUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
if (_tcscmp(pstrName, _T("circular")) == 0) {
SetCircular(_tcscmp(pstrValue, _T("true")) == 0);
}
else if (_tcscmp(pstrName, _T("clockwise")) == 0) {
SetClockwiseRotation(_tcscmp(pstrValue, _T("true")) == 0);
}
else if (_tcscmp(pstrName, _T("circlewidth")) == 0) SetCircleWidth(_ttoi(pstrValue));
else if (_tcscmp(pstrName, _T("bgcolor")) == 0) {
if (*pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetBgColor(clrColor);
}
else if (_tcscmp(pstrName, _T("fgcolor")) == 0) {
if (*pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetFgColor(clrColor);
}
else if (_tcscmp(pstrName, _T("indicator")) == 0)
{
SetIndicator(pstrValue);
}
else if (_tcscmp(pstrName, _T("enablecircleeffect")) == 0) {
SetEnableCircleEffect(_tcscmp(pstrValue, _T("true")) == 0);
}
else if (_tcscmp(pstrName, _T("gradientcolor1")) == 0) {
if (*pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetCircleGradientColor1(clrColor);
}
else if (_tcscmp(pstrName, _T("gradientcolor2")) == 0) {
if (*pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetCircleGradientColor2(clrColor);
}
else CProgressUI::SetAttribute(pstrName, pstrValue);
}
LPCTSTR CCircleProgressUI::GetClass() const
{
return DUI_CTR_CIRCLE_PROGRES;
}
LPVOID CCircleProgressUI::GetInterface(LPCTSTR pstrName)
{
if (_tcscmp(pstrName, DUI_CTR_CIRCLE_PROGRES) == 0) return static_cast<CCircleProgressUI*>(this);
return CProgressUI::GetInterface(pstrName);
}
} // namespace Duilib
除了增加以上两个部分外,还需要增加其他配套的代码:
在r\DuiLib\UIlib.h中增加头文件包含:
#include "Control/UIProgress.h"
//新增加代码
#include "Control/UICircleProgress.h"
#include "Control/UISlider.h"
在Core\UIDefine.h中增加宏定义:
#define DUI_CTR_CIRCLE_PROGRES (_T("CircleProgress"))
1
在DuiLib\Core\UIDlgBuilder.cpp文件中增加判断分支:
CControlUI* CDialogBuilder::_Parse(CMarkupNode* pRoot, CControlUI* pParent, CPaintManagerUI* pManager)
{
case 11:
if (_tcsicmp(pstrClass, DUI_CTR_CHILDLAYOUT) == 0) pControl = new CChildLayoutUI;
break;
case 14:
if( _tcsicmp(pstrClass, DUI_CTR_VERTICALLAYOUT) == 0 ) pControl = new CVerticalLayoutUI;
else if( _tcsicmp(pstrClass, DUI_CTR_LISTHEADERITEM) == 0 ) pControl = new CListHeaderItemUI;
//新增加代码
else if (_tcsicmp(pstrClass, DUI_CTR_CIRCLE_PROGRES) == 0) pControl = new CCircleProgressUI;
break;
}
通过以上步骤就可以在xml文件中进行控件布局了,示例布局代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<Window mininfo="200,260" size="260,320">
<Font shared="true" id="0" name="幼圆" size="12" default="true" />
<Font shared="true" id="1" name="微软雅黑" size="18" />
<VerticalLayout >
<CircleProgress name="progress1" circular="true" clockwise="true" enablecircleeffect="true"
gradientcolor1="#ff90EE90" gradientcolor2="#ff90EE90"
float="true" pos="10,10,0,0" height="125" width="125" circlewidth="20"
min="1" max="100" value="75" bgcolor="#ffA9A9A9" fgcolor="#ff90EE90"
valign="vcenter" textcolor="0xFFFFFFFF" font="2" text="在线:70![这里写图片描述](https://img-blog.csdn.net/20180527213749757?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW8zNDA0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)%"/>
</VerticalLayout>
</Window>
运行效果如下:
参考资料:
https://blog.csdn.net/fighton/article/details/72681889
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/c_base_jin/article/details/80472937