zoukankan      html  css  js  c++  java
  • Duilib的圆环形 进度条 实现(网易云信版本)

    /** @file CircleProgress.h
    * @brief 圆环型进度条控件,圆环中间可以有文本(如85%)
    * @copyright (c) 2019-2022, NetEase Inc. All rights reserved
    * @author Xuhuajie
    * @date 2019/8/14
    */

    #ifndef UI_CONTROL_CIRCLEPROGRESS_H_
    #define UI_CONTROL_CIRCLEPROGRESS_H_

    #pragma once

    namespace ui
    {

    class UILIB_API CircleProgress : public Progress
    {
    public:
    CircleProgress();

    /// 重写父类方法,提供个性化功能,请参考父类声明
    virtual void SetAttribute(const std::wstring& strName, const std::wstring& strValue) override;
    virtual void PaintStatusImage(IRenderContext* pRender) override;
    virtual void ClearImageCache() override;

    /**
    * @brief 设置圆形进度条
    * @param[in] bCircular 为 true 时设置为圆形滚动条,false 时设置为父级滚动条,默认为 true
    * @return 无
    */
    void SetCircular(bool bCircular = true);
    /**
    * @brief 设置递增方向
    * @param[in] bClockwise 为 true 时设置为顺时针,false 时设置为逆时针,默认为 true
    * @return 无
    */
    void SetClockwiseRotation(bool bClockwise = true);
    /**
    * @brief 设置圆环宽度
    * @param[in] nCircleWidth 宽度数值
    * @return 无
    */
    void SetCircleWidth(int nCircleWidth);
    /**
    * @brief 设置进度条背景颜色
    * @param[in] strColor要设置的背景颜色字符串,该字符串必须在 global.xml 中存在
    * @return 无
    */
    void SetBackgroudColor(const std::wstring& strColor);
    /**
    * @brief 设置进度条前景颜色
    * @param[in] strColor要设置的前景颜色字符串,该字符串必须在 global.xml 中存在
    * @return 无
    */
    void SetForegroudColor(const std::wstring& strColor);
    /**
    * @brief 设置进度条前景渐变颜色,与ForegroudColor同时使用,可以不设置,则无渐变效果
    * @param[in] strColor要设置的前景渐变颜色字符串,该字符串必须在 global.xml 中存在
    * @return 无
    */
    void SetCircleGradientColor(const std::wstring& strColor);
    /**
    * @brief 设置进度指示移动图标
    * @param[in] sIndicatorImage要设置的图片
    * @return 无
    */
    void SetIndicator(const std::wstring& sIndicatorImage);

    protected:
    bool m_bCircular;
    bool m_bClockwise;
    int m_nCircleWidth;
    DWORD m_dwBackgroundColor;
    DWORD m_dwForegroundColor;
    DWORD m_dwGradientColor;
    //Image m_IndicatorImage; //使用image对象,无法满足需求,需要设置矩阵变换
    Gdiplus::Image* m_pIndicator; //此类目前维护资源管理
    std::wstring m_sIndicatorImage;

    };

    } // namespace ui

    #endif // UI_CONTROL_CIRCLEPROGRESS_H_

    /** @file CircleProgress.cpp
    * @brief 圆环型滚动条控件,圆环中间可以有文本(如85%)
    * @copyright (c) 2019-2022, NetEase Inc. All rights reserved
    * @author Xuhuajie
    * @date 2019/8/14
    */

    #include "stdafx.h"
    #include "CircleProgress.h"
    #include "shlwapi.h"

    namespace ui
    {
    CircleProgress::CircleProgress() :
    m_bCircular(true),
    m_bClockwise(true),
    m_nCircleWidth(1),
    m_dwBackgroundColor(0),
    m_dwForegroundColor(0),
    m_dwGradientColor(0),
    m_pIndicator(nullptr)
    {

    }

    void CircleProgress::SetAttribute(const std::wstring& srName, const std::wstring& strValue)
    {
    if (srName == _T("circular")) SetCircular(strValue == _T("true"));
    else if (srName == _T("circlewidth")) SetCircleWidth(_ttoi(strValue.c_str()));
    else if (srName == _T("indicator")) SetIndicator(strValue);
    else if (srName == _T("clockwise")) SetClockwiseRotation(strValue == _T("true"));
    else if (srName == _T("bgcolor")) {
    LPCTSTR pValue = strValue.c_str();
    while (*pValue > _T('') && *pValue <= _T(' ')) pValue = ::CharNext(pValue);
    SetBackgroudColor(pValue);
    }
    else if (srName == _T("fgcolor")) {
    LPCTSTR pValue = strValue.c_str();
    while (*pValue > _T('') && *pValue <= _T(' ')) pValue = ::CharNext(pValue);
    SetForegroudColor(pValue);
    }
    else if (srName == _T("gradientcolor")) {
    LPCTSTR pValue = strValue.c_str();
    while (*pValue > _T('') && *pValue <= _T(' ')) pValue = ::CharNext(pValue);
    SetCircleGradientColor(pValue);
    }
    else Progress::SetAttribute(srName, strValue);
    }

    void CircleProgress::PaintStatusImage(IRenderContext* pRender)
    {
    Progress::PaintStatusImage(pRender);
    if (m_bCircular)
    {
    //目前IRenderContext还有很多GDI+接口未实现,暂时直接用gdi+画图了
    //以后可能会调整:需实现1、DrawArc 2、Pen增加brush(渐变)入参 3、可以自由设置Graphics属性
    int direction = m_bClockwise ? 1 : -1; //旋转方向
    int bordersize = 1; //弧度宽度目前使用1像素

    Gdiplus::Graphics graphics(pRender->GetDC());
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
    Gdiplus::Pen bgPen(m_dwBackgroundColor, m_nCircleWidth);
    // 圆形中心
    CPoint 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);
    //UiRect rcBorder; 仍然存在UiRect 到 RectF的转换,所以直接用gdi的RectF了
    Gdiplus::RectF rcBorder;
    rcBorder.X = center.x - side / 2;
    rcBorder.Y = center.y - side / 2;
    rcBorder.Width = 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_nCircleWidth, -0.5 * m_nCircleWidth);
    }
    outer.Inflate(-1, -1);


    if (m_dwGradientColor == 0)
    {
    //不使用渐变色,直接用前景色铺满
    Gdiplus::Pen fgPen(m_dwForegroundColor, m_nCircleWidth);
    graphics.DrawArc(&bgPen, outer, 270, 360); //270从最上面开始递增,设为0的话,是最右边开始
    graphics.DrawArc(&fgPen, outer, 270, direction * 360 * (m_nValue - m_nMin) / (m_nMax - m_nMin));
    }
    else
    {
    Gdiplus::REAL factors[4] = { 0.0f, 0.4f, 0.6f, 1.0f };
    Gdiplus::REAL positions[4] = { 0.0f, 0.2f, 0.8f, 1.0f };

    Gdiplus::LinearGradientBrush lgbrush(rcBorder, m_dwForegroundColor, m_dwGradientColor, Gdiplus::LinearGradientModeVertical);
    lgbrush.SetBlend(factors, positions, 4);
    graphics.DrawArc(&bgPen, outer, 270, 360);
    Gdiplus::Pen fgPen(&lgbrush, m_nCircleWidth);
    graphics.DrawArc(&fgPen, outer, 270, direction * 360 * (m_nValue - m_nMin) / (m_nMax - m_nMin));

    }

    //画旋转指示器图标,需要用到矩阵
    if (m_pIndicator)
    {
    Gdiplus::Matrix matrix;
    matrix.RotateAt(direction * 360 * (m_nValue - m_nMin) / (m_nMax - m_nMin), Gdiplus::PointF(center.x, center.y), Gdiplus::MatrixOrderAppend);
    graphics.SetTransform(&matrix);
    Gdiplus::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 CircleProgress::ClearImageCache()
    {
    __super::ClearImageCache();
    if (m_pIndicator)
    {
    delete m_pIndicator;
    m_pIndicator = nullptr;
    }
    }

    void CircleProgress::SetCircular(bool bCircular /*= true*/)
    {
    m_bCircular = bCircular;
    Invalidate();
    }


    void CircleProgress::SetClockwiseRotation(bool bClockwise /*= true*/)
    {
    if (bClockwise != m_bClockwise)
    {
    m_bClockwise = bClockwise;
    if (m_pIndicator)
    {
    //已经旋转了图片,旋转到相反的方向
    m_pIndicator->RotateFlip(Gdiplus::Rotate180FlipNone);
    }

    }
    }

    void CircleProgress::SetCircleWidth(int nCircleWidth)
    {
    m_nCircleWidth = nCircleWidth;
    Invalidate();
    }


    void CircleProgress::SetBackgroudColor(const std::wstring& strColor)
    {
    m_dwBackgroundColor = GlobalManager::GetTextColor(strColor);
    ASSERT(m_dwBackgroundColor != 0);
    Invalidate();
    }

    void CircleProgress::SetForegroudColor(const std::wstring& strColor)
    {
    m_dwForegroundColor = GlobalManager::GetTextColor(strColor);
    ASSERT(m_dwForegroundColor != 0);
    Invalidate();
    }

    void CircleProgress::SetIndicator(const std::wstring& sIndicatorImage)
    {
    if (m_sIndicatorImage != sIndicatorImage)
    {
    m_sIndicatorImage = sIndicatorImage;
    if (m_pIndicator)
    {
    delete m_pIndicator;
    m_pIndicator = nullptr;
    }
    std::wstring imagepath = m_sIndicatorImage;
    if (!::PathFileExistsW(imagepath.c_str())) {
    imagepath = GlobalManager::GetResourcePath() + m_pWindow->GetWindowResourcePath() + imagepath;
    }
    if (!::PathFileExistsW(imagepath.c_str())) {
    return;
    }
    m_pIndicator = new Gdiplus::Image(imagepath.c_str());

    Gdiplus::Status state = m_pIndicator->GetLastStatus();
    if (Gdiplus::Ok == state)
    {
    // 假定图片指向上
    m_pIndicator->RotateFlip(m_bClockwise ? Gdiplus::Rotate90FlipNone : Gdiplus::Rotate270FlipNone);
    Invalidate();
    }
    }
    }

    void CircleProgress::SetCircleGradientColor(const std::wstring& strColor)
    {
    m_dwGradientColor = GlobalManager::GetTextColor(strColor);
    ASSERT(m_dwGradientColor != 0);
    Invalidate();
    }
    }

  • 相关阅读:
    linux内核分析第八周理解进程调度时机跟踪分析进程调度与进程切换的过程
    linux内核分析第六周分析Linux内核创建一个新进程的过程
    Linux内核学习总结
    Linux内核分析第一周通过分析汇编代码理解计算机是如何工作的
    linux内核分析第五周分析system_call中断处理过程
    linux内核分析第三周跟踪分析Linux内核的启动过程
    转载:Understanding WPF Application Lifecycle
    Quick Sort 快速排序
    C#中的Immutable(不变的)
    一个lock和一个deadlock的例子
  • 原文地址:https://www.cnblogs.com/xuhuajie/p/11352714.html
Copyright © 2011-2022 走看看