WPF绘制测速仪表

 #region 公共参数
        // 原点位置
        Point Opos = new Point(200, 200);
        //总角度
        double angle = 360; // 角度
        //取模
        private static int num = 0;
        //刻度值0~100
        private int externalNum = 0;
        //最大刻度
        private int MaxScale = 51;
        //最小刻度
        private int MinScale = 0;
        //实际会绘制角度
        double drawAngle = 280.00;
        //圆的半径
        double radius = 200; // 圆半径

        #endregion

        public delegate void ExecuteMethodDelegate();

        public MainWindow()
        {
            InitializeComponent();

        }

        private Dictionary<string, Line> dicLine = new Dictionary<string, Line>();
        private int _num = 0;
        /// <summary>
        /// 画表盘的刻度
        /// </summary>
        private void ExternalScale()
        {
            this.radius = MainCanvas.Width / 2;
            double min = MinScale; double max = MaxScale;
            double step = drawAngle / (max - min);
            for (int i = 0; i < max - min; i++)
            {
                double angle1 = WrapAngle(i * step) + 90 + (360 - drawAngle) / 2;
                angle1 = ConvertDegreesToRadians(angle1);
                #region 绘制外圈线
                {

                    Line lineScale = new Line
                    {
                        X1 = (radius) * Math.Cos(angle1),
                        Y1 = (radius) * Math.Sin(angle1),
                        X2 = (radius - 15) * Math.Cos(angle1),
                        Y2 = (radius - 15) * Math.Sin(angle1),
                        Stroke = new SolidColorBrush(Color.FromRgb(227, 227, 226)),
                        StrokeThickness = 8
                    };
                    lineScale.Name = "line_" + _num;
                    Canvas.SetLeft(lineScale, Opos.X);
                    Canvas.SetTop(lineScale, Opos.Y);
                    MainCanvas.Children.Add(lineScale);
                    dicLine.Add("line_" + _num, lineScale);
                    _num += 2;
                }
                #endregion
                #region 绘制内圈点和数值
                {
                    Action<int, double, double> action = (t1, t2, t3) =>
                    {
                        Ellipse ellipse = new Ellipse
                        {
                            Stroke = new SolidColorBrush(Color.FromRgb(227, 227, 226)),
                            StrokeThickness = t1,
                            Fill = new SolidColorBrush(Color.FromRgb(227, 227, 226))
                        };
                        ellipse.SetValue(Canvas.LeftProperty, t2 - 5);
                        ellipse.SetValue(Canvas.TopProperty, t3 - 5);
                        MainCanvas.Children.Add(ellipse);
                    };
                    //double _step = externalNum >= 60 ? step - 0.28 : externalNum > 40 ? step - 0.149 : step;//刻度进行微调
                    double x1 = (radius - 45) * Math.Cos(angle1) + radius;
                    double y1 = (radius - 52) * Math.Sin(angle1) + radius;
                    if (num % 5 == 0)
                    {
                        //if (externalNum == 50)
                        //{
                        //    action(7, x1, y1);
                        //}
                        //else
                        //{
                        action(8, x1, y1);
                        //}

                        //添加刻度值
                        TextBlock txtScale = new TextBlock();
                        txtScale.Text = Convert.ToString(externalNum);
                        txtScale.FontSize = 10;
                        if (externalNum == 50)
                        {
                            Canvas.SetLeft(txtScale, ((radius - 65) * Math.Cos(angle1)) + radius - 6.6);
                            Canvas.SetTop(txtScale, ((radius - 65) * Math.Sin(angle1)) + radius - 8);
                        }
                        else
                        {
                            Canvas.SetLeft(txtScale, ((radius - 65) * Math.Cos(angle1)) + radius - 6.6);
                            Canvas.SetTop(txtScale, ((radius - 65) * Math.Sin(angle1)) + radius - 8);
                        }

                        MainCanvas.Children.Add(txtScale);
                        externalNum = externalNum + 10;
                        num = 0;
                    }
                    else
                    {
                        action(4, x1, y1);
                    }
                    num++;

                }

                #endregion
            }
            RotationAngle(0);//指针归零位
            DrawOCircle();
        }

        /// <summary>
        /// 圆形表心圆
        /// </summary>
        private void DrawOCircle()
        {
            Ellipse ellipseO = new Ellipse();
            ellipseO.Width = 5;
            ellipseO.Height = 5;
            ellipseO.Fill = Brushes.Black;

            Canvas.SetLeft(ellipseO, Opos.X - 2.5);
            Canvas.SetTop(ellipseO, Opos.Y - 2.5);
            //if (MainCanvas.Children.Contains(ellipseO))
            //    MainCanvas.Children.Remove(ellipseO);

            MainCanvas.Children.Add(ellipseO);
        }

        /// <summary>
        /// 计算指针旋转角度
        /// </summary>
        /// <param name="degrees"></param>
        /// <param name="maxNum"></param>
        /// <param name="minNum"></param>
        private void RotationAngle(double degrees)
        {
            double maxNum = 100; double minNum = 0;
            //表盘最小值 0 //表盘最大值 100
            double span = maxNum - minNum;
            double v = maxNum / span;
            var row = drawAngle / MaxScale * (degrees - MinScale) * v / 2 - 142;
            this.PointerCanvas.RenderTransform = SetAngleXY(row, Opos.X, Opos.Y);
            DispatcherHelper.UpdateUI();
        }

        /// <summary>
        /// 角度360度进制
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        private double WrapAngle(double angle)
        {
            return angle % 360;
        }

        /// <summary>
        /// 将角度转为弧度
        /// </summary>
        /// <param name="degrees"></param>
        /// <returns></returns>
        private double ConvertDegreesToRadians(double degrees)
        {
            double radians = (Math.PI / 180) * degrees;
            return radians;
        }

        /// <summary>
        /// 设置旋转角度和位置
        /// </summary>
        /// <param name="Angle">角度</param>
        /// <param name="CenterX">X轴偏移位置</param>
        /// <param name="CenterY">X轴偏移位置</param>
        /// <returns></returns>
        public TransformGroup SetAngleXY(double Angle, double CenterX, double CenterY)
        {
            TransformGroup tfGroup = new TransformGroup();
            RotateTransform rt = new RotateTransform();
            rt.Angle = Angle;
            rt.CenterX = CenterX;
            rt.CenterY = CenterY;
            tfGroup.Children.Add(rt);
            return tfGroup;
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
        {
            try
            {
                ExecuteMethodDelegate scale = ExternalScale;
                this.Dispatcher.BeginInvoke(scale);
                //scale?.BeginInvoke(null,null);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
                throw exception;
            }
        }

        public delegate void RotationAngleDelegate(double i);

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            double PreviousValue = 0, NextValue = 0;
            double[] arr = new double[] { 0, 1, 1.5, 2.5, 3.5, 7, 8.9, 9, 9.19, 9.23, 9.56, 9.58, 9.88, 9.99, 10.0, 10.12, 11, 12, 12.5, 15, 15.1, 15.23, 15.26, 15.27, 15.28, 15.5, 15.7, 15.9, 15.9, 16.12, 16.4, 16.8, 12.5 };
            //数值移动
            foreach (var item in arr)
            {
                PreviousValue = NextValue;
                NextValue = item;
                if (NextValue >= PreviousValue)//下一个值大于上一个值
                {
                    for (int i = 0; i < item; i += 2)
                    {
                        dicLine.TryGetValue("line_" + i, out Line line);
                        if (line != null)
                        {
                            line.Stroke = Brushes.Red;
                        }
                    }
                }
                else
                {
                    for (int i = Convert.ToInt32(NextValue) + 2; i <= PreviousValue; i += 2)
                    {
                        dicLine.TryGetValue("line_" + i, out Line line);
                        if (line != null)
                        {
                            line.Stroke = new SolidColorBrush(Color.FromRgb(227, 227, 226));
                        }
                    }
                }

                RotationAngleDelegate rotationAngle = RotationAngle;
                this.Dispatcher.Invoke(rotationAngle, item);
                Thread.Sleep(200);
                Console.WriteLine($"i的值:{item}");
            }
        }

        private void ResetBtn_OnClick(object sender, RoutedEventArgs e)
        {
            RotationAngleDelegate rotationAngle = RotationAngle;
            rotationAngle.Invoke(0);
            foreach (var item in dicLine)
            {
                item.Value.Stroke = new SolidColorBrush(Color.FromRgb(227, 227, 226));
            }
        }

前台代码:

<Canvas x:Name="MainCanvas" 
                Width="400"
                Height="400">
        </Canvas>
        <Canvas x:Name="PointerCanvas" Width="{Binding Width,ElementName=MainCanvas}"
                 Height="{Binding Height,ElementName=MainCanvas}">
            <Path Stroke="Black" Canvas.Left="187.5" Canvas.Top="2" StrokeThickness="0">
                <Path.Data>
                    <PathGeometry>
                        <PathGeometry.Figures>
                            <PathFigure StartPoint="5,200" IsClosed="True">
                                <PathFigure.Segments>
                                    <LineSegment Point="17,80" ></LineSegment>
                                    <LineSegment Point="19,201" ></LineSegment>
                                    <LineSegment Point="12,208" ></LineSegment>
                                </PathFigure.Segments>
                            </PathFigure>
                        </PathGeometry.Figures>
                    </PathGeometry>
                </Path.Data>
                <Path.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                        <GradientStop Color="#F7D47E" Offset="0.25"></GradientStop>
                        <GradientStop Color="#F5CE72" Offset="0.5"></GradientStop>
                        <GradientStop Color="#F4B33C" Offset="0.75"></GradientStop>
                        <GradientStop Color="#F3A71C" Offset="1"></GradientStop>
                    </LinearGradientBrush>
                </Path.Fill>
            </Path>
        </Canvas>
        <Button Content="Button" HorizontalAlignment="Left" Click="ButtonBase_OnClick" Margin="30,38,0,0" VerticalAlignment="Top" Width="76"/>
        <Button Content="重置" HorizontalAlignment="Left" Click="ResetBtn_OnClick" Margin="30,97,0,0" VerticalAlignment="Top" Width="74"/>



注:

这里解析一下:+ 90 + (360 - drawAngle) / 2 是为什么(下面的图也是从别人那偷来的)

如果按照图示:+ 90 + (360 - 240) / 2 ;240是指绘制的表盘是多少度。起点是从右边0点开始

效果:

本文作者:admin

本文链接:https://www.javalc.com/post/79.html

版权声明:本篇文章于2021-10-18,由admin发表,转载请注明出处:分享你我。如有疑问,请联系我们

WPF 绘制仪表

发表评论

取消
扫码支持