• 如何实现圆形的进度条(ProgressBar)


          在我们实际的工作中可能经常使用到圆形的进度条,但是这是怎么实现的呢?其实这只不过是修改了一下ProgressBar的模板,我们在下面的代码中我们将ProgressBar的Value值绑定到Border的Background上面,并且使用了一个ValueToProcessConverter的转换器进行相应地转换,这里重点介绍一下这个转换器

    <ProgressBar Name="pb" Minimum="0" Maximum="100" >
        <ProgressBar.Template>
           <ControlTemplate TargetType="ProgressBar">
              <Border Background="{TemplateBinding Value, Converter={StaticResource ValueToProcessConverter}, ConverterParameter=250}"/>
           </ControlTemplate>
        </ProgressBar.Template>
    </ProgressBar>

    下面介绍这部分的源码,并做简要的分析:

          首先,获取ProgressBar.Value,然后再获取ConverterParameter=250这个值,通过这两个值就能确定画的圆环的大小和ProgressBar显示的值,然后我们再调用DrawBrush(arg, 100, radius, radius, Thickness)这个函数来进行绘制,具体代码如下:         

    private Brush DrawBrush(double value, double maxValue, double radiusX, double radiusY, double thickness)
            {
                DrawingGroup drawingGroup = new DrawingGroup();
                DrawingContext drawingContext = drawingGroup.Open();
                DrawingGeometry(drawingContext, value, maxValue, radiusX, radiusY, thickness);
                DrawingBrush brush = new DrawingBrush(drawingGroup);
                return brush;
            }
    

      这里需要注意的是绝不能直接实例化 DrawingContext;但可以通过某些方法(例如 DrawingGroup.Open 和 DrawingVisual.RenderOpen)获取绘图上下文。我们这里是使用DrawingGroup.Open的方法来进行相应的绘图,然后在里面调用里DrawingGeometry这个函数,在这个函数中开始绘制一些DrawEllipse和DrawGeometry,在这个函数中我们讲解一下FormattedText 这个类,使用 FormattedText 对象可以绘制多行文本,且可以单独对该文本中的每个字符设置格式。

     private void DrawingGeometry(DrawingContext drawingContext, double value, double maxValue, double radiusX, double radiusY, double thickness)
            {
                drawingContext.DrawEllipse(null, new Pen(EllipseBrush, thickness), centerPoint, radiusX, radiusY);
                drawingContext.DrawGeometry(NormalBrush, new Pen(), GetGeometry(value, maxValue, radiusX, radiusY, thickness));
    
                FormattedText formatWords = new FormattedText(percentString, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, SuccessRateTypeface, SuccessRateFontSize, NormalBrush);
                Point startPoint = new Point(centerPoint.X - formatWords.Width / 2, centerPoint.Y - formatWords.Height / 2 - SuccessRateFontCorrectionValue);
                drawingContext.DrawText(formatWords, startPoint);
    
                drawingContext.Close();
            }  
    public class ValueToProcessConverter : IValueConverter
        {
            readonly double Thickness = 20;
            private Point centerPoint;
            private double radius;
            readonly SolidColorBrush NormalBrush = new SolidColorBrush(Colors.White);
            readonly SolidColorBrush EllipseBrush = new SolidColorBrush(Color.FromRgb(107, 132, 165));
    
            string percentString;
            private static readonly Typeface SuccessRateTypeface;
            private const int SuccessRateFontSize = 65;
            readonly double SuccessRateFontCorrectionValue = 12;
    
            static ValueToProcessConverter()
            {
                SuccessRateTypeface = new Typeface(new FontFamily("MSYH"), new FontStyle(), new FontWeight(), new FontStretch());
            }
            public ValueToProcessConverter()
            {
    
            }
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value is double && !string.IsNullOrEmpty((string)parameter))
                {
                    double arg = (double)value;
                    double width = double.Parse((string)parameter);
                    radius = width / 2;
                    centerPoint = new Point(radius, radius);
                    return DrawBrush(arg, 100, radius, radius, Thickness);
                }
                else
                {
                    throw new ArgumentException();
                }
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
    
            /// <summary>
            /// 根据角度获取坐标
            /// </summary>
            /// <param name="CenterPoint"></param>
            /// <param name="r"></param>
            /// <param name="angel"></param>
            /// <returns></returns>
            private Point GetPointByAngel(Point CenterPoint, double r, double angel)
            {
                Point p = new Point();
                p.X = Math.Sin(angel * Math.PI / 180) * r + CenterPoint.X;
                p.Y = CenterPoint.Y - Math.Cos(angel * Math.PI / 180) * r;
                return p;
            }
    
            /// <summary>
            /// 根据4个坐标画出扇形
            /// </summary>
            /// <param name="bigFirstPoint"></param>
            /// <param name="bigSecondPoint"></param>
            /// <param name="smallFirstPoint"></param>
            /// <param name="smallSecondPoint"></param>
            /// <param name="bigRadius"></param>
            /// <param name="smallRadius"></param>
            /// <param name="isLargeArc"></param>
            /// <returns></returns>
            private Geometry DrawingArcGeometry(Point bigFirstPoint, Point bigSecondPoint, Point smallFirstPoint, Point smallSecondPoint, double bigRadius, double smallRadius, bool isLargeArc)
            {
                PathFigure pathFigure = new PathFigure { IsClosed = true };
                pathFigure.StartPoint = bigFirstPoint;
                pathFigure.Segments.Add(
                  new ArcSegment
                  {
                      Point = bigSecondPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(bigRadius, bigRadius),
                      SweepDirection = SweepDirection.Clockwise
                  });
                pathFigure.Segments.Add(new LineSegment { Point = smallSecondPoint });
                pathFigure.Segments.Add(
                 new ArcSegment
                 {
                     Point = smallFirstPoint,
                     IsLargeArc = isLargeArc,
                     Size = new Size(smallRadius, smallRadius),
                     SweepDirection = SweepDirection.Counterclockwise
                 });
                PathGeometry pathGeometry = new PathGeometry();
                pathGeometry.Figures.Add(pathFigure);
    
                return pathGeometry;
            }
    
            /// <summary>
            /// 根据当前值和最大值获取扇形
            /// </summary>
            /// <param name="value"></param>
            /// <param name="maxValue"></param>
            /// <returns></returns>
            private Geometry GetGeometry(double value, double maxValue, double radiusX, double radiusY, double thickness)
            {
                bool isLargeArc = false;
                double percent = value / maxValue;
                percentString = string.Format("{0}%", Math.Round(percent * 100, 2));
                double angel = percent * 360D;
                if (angel > 180) isLargeArc = true;
                double bigR = radiusX + thickness / 2;
                double smallR = radiusX - thickness / 2;
                Point firstpoint = GetPointByAngel(centerPoint, bigR, 0);
                Point secondpoint = GetPointByAngel(centerPoint, bigR, angel);
                Point thirdpoint = GetPointByAngel(centerPoint, smallR, 0);
                Point fourpoint = GetPointByAngel(centerPoint, smallR, angel);
                return DrawingArcGeometry(firstpoint, secondpoint, thirdpoint, fourpoint, bigR, smallR, isLargeArc);
            }
    
            /// <summary>
            /// 画扇形
            /// </summary>
            /// <param name="drawingContext"></param>
            /// <param name="value"></param>
            /// <param name="maxValue"></param>
            /// <param name="radiusX"></param>
            /// <param name="radiusY"></param>
            /// <param name="thickness"></param>
            private void DrawingGeometry(DrawingContext drawingContext, double value, double maxValue, double radiusX, double radiusY, double thickness)
            {
                drawingContext.DrawEllipse(null, new Pen(EllipseBrush, thickness), centerPoint, radiusX, radiusY);
                drawingContext.DrawGeometry(NormalBrush, new Pen(), GetGeometry(value, maxValue, radiusX, radiusY, thickness));
                FormattedText formatWords = new FormattedText(percentString, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, SuccessRateTypeface, SuccessRateFontSize, NormalBrush);
                Point startPoint = new Point(centerPoint.X - formatWords.Width / 2, centerPoint.Y - formatWords.Height / 2 - SuccessRateFontCorrectionValue);
                drawingContext.DrawText(formatWords, startPoint);
                drawingContext.Close();
            }
    
            /// <summary>
            /// 根据当前值和最大值画出进度条
            /// </summary>
            /// <param name="value"></param>
            /// <param name="maxValue"></param>
            /// <returns></returns>
            private Brush DrawBrush(double value, double maxValue, double radiusX, double radiusY, double thickness)
            {
                DrawingGroup drawingGroup = new DrawingGroup();
                DrawingContext drawingContext = drawingGroup.Open();
                DrawingGeometry(drawingContext, value, maxValue, radiusX, radiusY, thickness);
                DrawingBrush brush = new DrawingBrush(drawingGroup);
                return brush;
            }
    
        }
    

      

  • 相关阅读:
    [ARC101C] Ribbons on Tree
    NOIP2020 模拟赛 B 组 Day6
    #10471. 「2020-10-02 提高模拟赛」灌溉 (water)
    #10470. 「2020-10-02 提高模拟赛」流水线 (line)
    一类巧妙利用利用失配树的序列DP
    学军中学csp-noip2020模拟5
    信号与槽-高级应用
    PyQt5中的布局管理-QSplitter
    PyQt5中的布局管理-嵌套布局
    信号与槽-入门应用
  • 原文地址:https://www.cnblogs.com/seekdream/p/4678659.html
Copyright © 2020-2023  润新知