Visual c++ 使用Direct2D绘制圆形进度条

Visual c++ 使用Direct2D绘制圆形进度条,visual-c++,progress-bar,direct2d,Visual C++,Progress Bar,Direct2d,我正在创建一个圆形进度条控件,并使用Direct2D绘制它 我想得到这样的东西: 我很难想出如何画这种梯度。我已经实现了用纯色画笔或使用不同的渐变(线性、径向)绘制进度,但我无法按照图像中的条形绘制渐变 这就是我现在拥有的: 谁能给我一个提示,我要用什么样的刷子才能得到我想要的 提前谢谢 我想要一个圆弧渐变…类似这样的东西: 我只是制定了这个的初始版本,不确定这是否是您想要的,仅供参考 最终效果 编程步骤如下: 创建圆的轮廓(可以通过组合两个椭圆来创建几何图形组) 创建半径渐变笔刷,使用此

我正在创建一个圆形进度条控件,并使用Direct2D绘制它

我想得到这样的东西:

我很难想出如何画这种梯度。我已经实现了用纯色画笔或使用不同的渐变(线性、径向)绘制进度,但我无法按照图像中的条形绘制渐变

这就是我现在拥有的:

谁能给我一个提示,我要用什么样的刷子才能得到我想要的

提前谢谢

我想要一个圆弧渐变…类似这样的东西:


我只是制定了这个的初始版本,不确定这是否是您想要的,仅供参考

最终效果

编程步骤如下:
  • 创建圆的轮廓(可以通过组合两个椭圆来创建几何图形组)
  • 创建半径渐变笔刷,使用此笔刷填充圆
  • 在每个帧中旋转渐变笔刷以产生进度条的旋转效果
  • 完整代码: 注意,您需要链接d2d1.lib和winmm.lib使其工作

    由于您熟悉Direct2D,因此我不打算详细介绍代码,如果您需要进一步讨论,请留下评论。谢谢您还可以在github上下载完整的项目

    #包括
    #如果(P){P->RELEASE();P=NULL;}
    常数int几何体_计数=2;
    ID2D1Factory*g_pD2DFactory=NULL;//Direct2D工厂
    ID2D1HwndRenderTarget*g_pRenderTarget=NULL;//渲染目标
    ID2D1SolidColorBrush*g_pBlackBrush=NULL;//轮廓刷
    ID2D1RadialGradientBrush*g_pRadialGradientBrush=NULL;//径向梯度刷
    //2圈以建立几何图形组。这是进度条的概要
    D2D1_椭圆g_椭圆E0=D2D1::椭圆(D2D1::Point2F(300300),150150);
    D2D1_椭圆g_椭圆E1=D2D1::椭圆(D2D1::Point2F(300300),200200);
    D2D1_椭圆g_椭圆[几何体计数]=
    {
    g_Ellipse0,
    g_Ellipse1,
    };
    ID2D1Ellipsegometry*g_Pellipsarray[几何体计数]={NULL};
    ID2D1GeometryGroup*g_PGGeometryGroup=NULL;
    VOID CreateD2DResource(HWND HWND)
    {
    如果(!g_pRenderTarget)
    {
    HRESULT-hr;
    hr=D2D1CreateFactory(D2D1\u工厂类型\u单螺纹,&g\u pD2DFactory);
    如果(失败(小时))
    {
    MessageBox(hWnd,“创建D2D工厂失败!”,“错误”,0);
    返回;
    }
    //获取绘图区域的大小
    RECT-rc;
    GetClientRect(hWnd和rc);
    //创建Direct2D渲染目标
    hr=g_pD2DFactory->CreateHwnRenderTarget(
    D2D1::RenderTargetProperties(),
    D2D1::HwndRenderTargetProperties(
    hWnd,
    D2D1::SizeU(右栏-左栏,下栏-上栏)
    ), 
    &g_pRenderTarget
    ) ;
    如果(失败(小时))
    {
    MessageBox(hWnd,“创建渲染目标失败!”,“错误”,0);
    返回;
    }
    //创建轮廓笔刷(黑色)
    hr=g_pRenderTarget->CreateSolidColorBrush(
    D2D1::ColorF(D2D1::ColorF::黑色),
    &g_pBlackBrush
    ) ;
    如果(失败(小时))
    {
    MessageBox(hWnd,“创建轮廓笔刷(黑色)失败!”,“错误”,0);
    返回;
    }
    //定义渐变停止点
    D2D1_梯度_停止梯度停止[2];
    gradientStops[0]。color=D2D1::ColorF(D2D1::ColorF::Blue);
    渐变停止[0]。位置=0.f;
    gradientStops[1]。color=D2D1::ColorF(D2D1::ColorF::White);
    渐变停止[1]。位置=1.f;
    //创建渐变停止集合
    ID2D1GradientStopCollection*pGradientStops=NULL;
    hr=g_pRenderTarget->CreateGradientStopCollection(
    梯度停止,
    2.
    D2D1_伽马_2_2,
    D2D1_延伸_模式_夹具,
    &pGradientStops
    ) ;
    如果(失败(小时))
    {
    MessageBox(NULL,“创建梯度停止收集失败!”,“错误”,0);
    }
    //创建线性渐变笔刷以填充椭圆
    hr=g_pRenderTarget->CreateAradialGradientBrush(
    D2D1::RadialGradientBrushProperties(
    D2D1::点2F(170170),
    D2D1::点2F(0,0),
    150,
    150),
    pGradientStops,
    &g_pRadialGradientBrush
    ) ;
    如果(失败(小时))
    {
    MessageBox(hWnd,“创建线性渐变笔刷失败!”,“错误”,0);
    返回;
    }
    //创建2个椭圆。
    对于(int i=0;iCreateEllipsegometry(g_Ellipse[i],&g_Pellipsarray[i]);
    如果(失败(小时))
    {
    MessageBox(hWnd,“创建椭圆几何体失败!”,“错误”,0);
    返回;
    }
    }
    //创建几何图形组,两个圆组成一个组。
    hr=g_pD2DFactory->CreateGeometryGroup(
    D2D1_填充_模式_备用,
    (ID2D1Geometry**)和g_Pellipsarray,
    排列(g_Pellipsarray),
    &g_pGeometryGroup
    );
    }
    }
    无效渲染(HWND HWND)
    {
    //旋转总角度
    静态浮动总角度=0.0f;
    //最后一次
    静态DWORD lastTime=timeGetTime();
    //获取当前时间
    DWORD currentTime=timeGetTime();
    //计算当前帧中经过的时间。
    浮动时间增量=(浮动)(当前时间-上次时间)*0.1;
    //按当前帧中经过的时间增加totalAngle。
    总角度+=时间增量;
    创建数据源(hwnd);
    g_pRenderTarget->BeginDraw();
    //将背景色清除为白色
    g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    //绘制几何图形组
    g_pRenderTarget->DrawGeometry(g_pGeometryGroup,g
    
    #include <D2D1.h>
    
    #define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
    const int GEOMETRY_COUNT = 2;
    
    ID2D1Factory*           g_pD2DFactory   = NULL; // Direct2D factory
    ID2D1HwndRenderTarget*  g_pRenderTarget = NULL; // Render target
    ID2D1SolidColorBrush*   g_pBlackBrush   = NULL; // Outline brush
    ID2D1RadialGradientBrush* g_pRadialGradientBrush = NULL ; // Radial gradient brush
    
    // 2 circle to build up a geometry group. this is the outline of the progress bar
    D2D1_ELLIPSE g_Ellipse0 = D2D1::Ellipse(D2D1::Point2F(300, 300), 150, 150);
    D2D1_ELLIPSE g_Ellipse1 = D2D1::Ellipse(D2D1::Point2F(300, 300), 200, 200);
    
    D2D1_ELLIPSE g_Ellipse[GEOMETRY_COUNT] = 
    {
        g_Ellipse0, 
        g_Ellipse1,
    };
    
    ID2D1EllipseGeometry* g_pEllipseArray[GEOMETRY_COUNT] = { NULL };
    ID2D1GeometryGroup* g_pGeometryGroup = NULL;
    
    VOID CreateD2DResource(HWND hWnd)
    {
        if (!g_pRenderTarget)
        {
            HRESULT hr ;
    
            hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory) ;
            if (FAILED(hr))
            {
                MessageBox(hWnd, "Create D2D factory failed!", "Error", 0) ;
                return ;
            }
    
            // Obtain the size of the drawing area
            RECT rc ;
            GetClientRect(hWnd, &rc) ;
    
            // Create a Direct2D render target
            hr = g_pD2DFactory->CreateHwndRenderTarget(
                D2D1::RenderTargetProperties(),
                D2D1::HwndRenderTargetProperties(
                hWnd, 
                D2D1::SizeU(rc.right - rc.left,rc.bottom - rc.top)
                ), 
                &g_pRenderTarget
                ) ;
            if (FAILED(hr))
            {
                MessageBox(hWnd, "Create render target failed!", "Error", 0) ;
                return ;
            }
    
            // Create the outline brush(black)
            hr = g_pRenderTarget->CreateSolidColorBrush(
                D2D1::ColorF(D2D1::ColorF::Black),
                &g_pBlackBrush
                ) ;
            if (FAILED(hr))
            {
                MessageBox(hWnd, "Create outline brush(black) failed!", "Error", 0) ;
                return ;
            }
    
            // Define gradient stops
            D2D1_GRADIENT_STOP gradientStops[2] ;
            gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Blue) ;
            gradientStops[0].position = 0.f ;
            gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::White) ;
            gradientStops[1].position = 1.f ;
    
            // Create gradient stops collection
            ID2D1GradientStopCollection* pGradientStops = NULL ;
            hr = g_pRenderTarget->CreateGradientStopCollection(
                gradientStops,
                2, 
                D2D1_GAMMA_2_2,
                D2D1_EXTEND_MODE_CLAMP,
                &pGradientStops
                ) ;
            if (FAILED(hr))
            {
                MessageBox(NULL, "Create gradient stops collection failed!", "Error", 0);
            }
    
            // Create a linear gradient brush to fill in the ellipse
            hr = g_pRenderTarget->CreateRadialGradientBrush(
                D2D1::RadialGradientBrushProperties(
                D2D1::Point2F(170, 170),
                D2D1::Point2F(0, 0),
                150,
                150),
                pGradientStops,
                &g_pRadialGradientBrush
                ) ;
    
            if (FAILED(hr))
            {
                MessageBox(hWnd, "Create linear gradient brush failed!", "Error", 0) ;
                return ;
            }
    
            // Create the 2 ellipse.
            for (int i = 0; i < GEOMETRY_COUNT; ++i)
            {
                hr = g_pD2DFactory->CreateEllipseGeometry(g_Ellipse[i], &g_pEllipseArray[i]);
                if (FAILED(hr)) 
                {
                    MessageBox(hWnd, "Create Ellipse Geometry failed!", "Error", 0);
                    return;
                }
            }
    
            // Create the geometry group, the 2 circles make up a group.
            hr = g_pD2DFactory->CreateGeometryGroup(
                D2D1_FILL_MODE_ALTERNATE,
                (ID2D1Geometry**)&g_pEllipseArray,
                ARRAYSIZE(g_pEllipseArray),
                &g_pGeometryGroup
            );
        }
    }
    
    VOID Render(HWND hwnd)
    {
        // total angle to rotate
        static float totalAngle = 0.0f;
    
        // Get last time
        static DWORD lastTime = timeGetTime();
    
        // Get current time
        DWORD currentTime = timeGetTime();
    
        // Calculate time elapsed in current frame.
        float timeDelta = (float)(currentTime - lastTime) * 0.1;
    
        // Increase the totalAngle by the time elapsed in current frame.
        totalAngle += timeDelta;
    
        CreateD2DResource(hwnd) ;
    
        g_pRenderTarget->BeginDraw() ;
    
        // Clear background color to White
        g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    
        // Draw geometry group
        g_pRenderTarget->DrawGeometry(g_pGeometryGroup, g_pBlackBrush);
    
        // Roatate the gradient brush based on the total elapsed time
        D2D1_MATRIX_3X2_F rotMatrix = D2D1::Matrix3x2F::Rotation(totalAngle, D2D1::Point2F(300, 300));
        g_pRadialGradientBrush->SetTransform(rotMatrix);
    
        // Fill geometry group with the transformed brush
        g_pRenderTarget->FillGeometry(g_pGeometryGroup, g_pRadialGradientBrush);
    
        HRESULT hr = g_pRenderTarget->EndDraw() ;
        if (FAILED(hr))
        {
            MessageBox(NULL, "Draw failed!", "Error", 0) ;
            return ;
        }
    
        // Update last time to current time for next loop
        lastTime = currentTime;
    }
    
    VOID Cleanup()
    {
        SAFE_RELEASE(g_pRenderTarget) ;
        SAFE_RELEASE(g_pBlackBrush) ;
        SAFE_RELEASE(g_pGeometryGroup);
        SAFE_RELEASE(g_pRadialGradientBrush);
    
        for (int i = 0; i < GEOMETRY_COUNT; ++i)
        {
            SAFE_RELEASE(g_pEllipseArray[i]);
            g_pEllipseArray[i] = NULL;
        }
    
        SAFE_RELEASE(g_pD2DFactory) ;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)   
    {
        switch (message)    
        {
        case   WM_PAINT:
            Render(hwnd) ;
            return 0 ;
    
        case WM_KEYDOWN: 
            { 
                switch( wParam ) 
                { 
                case VK_ESCAPE: 
                    SendMessage( hwnd, WM_CLOSE, 0, 0 ); 
                    break ; 
                default: 
                    break ; 
                } 
            } 
            break ; 
    
        case WM_DESTROY: 
            Cleanup(); 
            PostQuitMessage( 0 ); 
            return 0; 
        }
    
        return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    
    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
    {
    
        WNDCLASSEX winClass ;
    
        winClass.lpszClassName = "Direct2D";
        winClass.cbSize        = sizeof(WNDCLASSEX);
        winClass.style         = CS_HREDRAW | CS_VREDRAW;
        winClass.lpfnWndProc   = WndProc;
        winClass.hInstance     = hInstance;
        winClass.hIcon         = NULL ;
        winClass.hIconSm       = NULL ;
        winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        winClass.hbrBackground = NULL ;
        winClass.lpszMenuName  = NULL;
        winClass.cbClsExtra    = 0;
        winClass.cbWndExtra    = 0;
    
        if (!RegisterClassEx (&winClass))   
        {
            MessageBox ( NULL, TEXT( "This program requires Windows NT!" ), "error", MB_ICONERROR) ;
            return 0 ;  
        }   
    
        HWND hwnd = CreateWindowEx(NULL,  
            "Direct2D",                 // window class name
            "Circular Progressbar",         // window caption
            WS_OVERLAPPEDWINDOW,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            600,                        // initial x size
            600,                        // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL) ;                     // creation parameters
    
            ShowWindow (hwnd, iCmdShow) ;
            UpdateWindow (hwnd) ;
    
            MSG msg ;  
            ZeroMemory(&msg, sizeof(msg)) ;
    
            while (GetMessage (&msg, NULL, 0, 0))  
            {
                TranslateMessage (&msg) ;
                DispatchMessage (&msg) ;
            }
    
            return msg.wParam ;
    }