WPF模拟时钟

本文详细介绍了一款使用WPF技术实现的模拟时钟应用程序,包括XAML布局、计时器处理、时钟指针绘制及时间显示更新的完整代码与逻辑。通过精确的数学计算和UI元素操作,实现了时、分、秒针的动态旋转效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、运行效果图

源代码链接https://download.csdn.net/download/afu1972715000/11966103

二、xaml

<Window x:Class="WpfClock.WindowClock"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfClock"
        mc:Ignorable="d"
        Title="WindowClock" Height="600" Width="1280" WindowStartupLocation="CenterScreen">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Canvas Grid.Column="0" Name="AnalogCanvs" Width="500" Height="500" >
            <!--<Label Content="08:08:08" FontSize="16" Foreground="Black" Height="Auto" HorizontalAlignment="Center" Name="labTime2" VerticalAlignment="Bottom" Width="Auto" Canvas.Left="201" Canvas.Top="320" />-->
        </Canvas>
        <Canvas Grid.Column="1" Name="digitCanvas" Width="600" Margin="18,35,18,135" >
            <Grid Width="300" Height="300">

                <Image Source="images/clock.png"></Image>
                <!--<Label Name="lab商标" Foreground="White" Margin="0,0,0,211" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="Auto" Width="Auto" FontSize="13" >JackMoon</Label>
                <Label Name="lab创建时间" Foreground="White" Margin="0,91,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" Height="Auto" Width="Auto">1987</Label>-->
                <!-- 秒针定义  -->
                <Rectangle Margin="150,0,149,150" Name="rectangleSecond" Stroke="White" Height="120" VerticalAlignment="Bottom" Width="1">
                    <Rectangle.RenderTransform>
                        <RotateTransform x:Name="secondPointer" CenterX="0" CenterY="120" Angle="0" />
                    </Rectangle.RenderTransform>
                </Rectangle>
                <!-- -->
                <!-- 分钟定义  -->
                <Rectangle Margin="150,49,149,151" Name="rectangleMinute" Stroke="LightGreen" Width="1">
                    <Rectangle.RenderTransform>
                        <RotateTransform x:Name="minutePointer" CenterX="0" CenterY="100" Angle="45" />
                    </Rectangle.RenderTransform>
                </Rectangle>
                <!-- -->
                <!-- 时针定义  -->
                <Rectangle Margin="150,80,149,150" Name="rectangleHour" Stroke="LightYellow" Width="1">
                    <Rectangle.RenderTransform>
                        <RotateTransform x:Name="hourPointer" CenterX="0" CenterY="70" Angle="90" />
                    </Rectangle.RenderTransform>
                </Rectangle>
                <!---->
              <Label Content="08:08:08" FontSize="16" Foreground="White" Height="Auto" HorizontalAlignment="Center" Margin="114,0,113,86" Name="labTime" VerticalAlignment="Bottom" Width="Auto" />
            </Grid>
        </Canvas>
    </Grid>
</Window>
三、代码

namespace WpfClock
{
    /// <summary>
    /// WindowClock.xaml 的交互逻辑
    /// </summary>
    public partial class WindowClock : Window
    {
        // 共用字段
        DispatcherTimer timer = new DispatcherTimer();  // 计时器
        DateTime CurrTime = DateTime.Now;                   // 当前时间

        // 模拟时钟字段定义
        double radius = 250;                              // 圆半径
        double angle = 360;                               // 角度
        Point Opos = new Point();                       // 原点位置
        Line HourLine, MinuLine, SecdLine;           // 时针、分针、秒针
        Label numberClock = new Label();

        //计时器
        System.Timers.Timer timer2 = new System.Timers.Timer(1000);

        public WindowClock()
        {
            InitializeComponent();

            // 原点位置
            Opos = new Point(250, 250);

            // 初始化计时器
            timer.Interval = TimeSpan.FromMilliseconds(100);
            timer.Tick += Timer_Tick;
            timer.IsEnabled = true;
            timer.Start();

            // 初始化时钟针
            HourLine = new Line();
            MinuLine = new Line();
            SecdLine = new Line();

            DrawCircle();
            DrawDigit();
            DrawGridLine();
            DrawOCircle();
            DrawNumerClock();


            #region 初始化时间
            secondPointer.Angle = DateTime.Now.Second * 6;
            minutePointer.Angle = DateTime.Now.Minute * 6;
            hourPointer.Angle = (DateTime.Now.Hour * 30) + (DateTime.Now.Minute * 0.5);
            this.labTime.Content = DateTime.Now.ToString("HH:mm:ss");
            #endregion
            timer2.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer2.Enabled = true;
        }

        private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            //UI异步更新
            this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
            {
                //秒针转动,秒针绕一圈360度,共60秒,所以1秒转动6度
                secondPointer.Angle = DateTime.Now.Second * 6;
                //分针转动,分针绕一圈360度,共60分,所以1分转动6度
                minutePointer.Angle = DateTime.Now.Minute * 6;
                //时针转动,时针绕一圈360度,共12时,所以1时转动30度。
                //另外同一个小时内,随着分钟数的变化(绕一圈60分钟),时针也在缓慢变化(转动30度,30/60=0.5)
                hourPointer.Angle = (DateTime.Now.Hour * 30) + (DateTime.Now.Minute * 0.5);
                //更新时间值
                this.labTime.Content = DateTime.Now.ToString("HH:mm:ss");
                //更新时间值
                //this.labTime2.Content = DateTime.Now.ToString("HH:mm:ss");
            }));
        }

        /// <summary>
        /// 画表盘外圆
        /// </summary>
        private void DrawCircle()
        {
            Ellipse ellipse = new Ellipse();
            ellipse.Stroke = Brushes.DarkGray;
            ellipse.StrokeThickness = 4;
            ellipse.Width = 500;
            ellipse.Height = 500;
            ellipse.Fill = Brushes.Gray;

            Canvas.SetLeft(ellipse, 0);
            Canvas.SetTop(ellipse, 0);

            AnalogCanvs.Children.Add(ellipse);

            Ellipse ellipse1 = new Ellipse();
            ellipse1.Stroke = Brushes.Gray;
            ellipse1.StrokeThickness = 2;
            ellipse1.Width = 510;
            ellipse1.Height = 510;

            Canvas.SetLeft(ellipse1, -5);
            Canvas.SetTop(ellipse1, -5);
            AnalogCanvs.Children.Add(ellipse1);
        }

        ///<summary>
        ///画数字时钟
        ///</summary>
        private void DrawNumerClock()
        {
            //< Label Content = "08:08:08" FontSize = "16" Foreground = "Black" Height = "Auto" HorizontalAlignment = "Center" 
            //    Name = "labTime2" VerticalAlignment = "Bottom" Width = "Auto" Canvas.Left = "201" Canvas.Top = "320" />
            //Label numberClock = new Label();
            numberClock.Name = "labTime2";
            numberClock.Content = "08:08:08";
            numberClock.FontSize = 16;
            numberClock.Foreground = new SolidColorBrush(Colors.White); //用固态画刷填充前景色
            Canvas.SetLeft(numberClock, 220);
            Canvas.SetTop(numberClock, 320);
            AnalogCanvs.Children.Add(numberClock);
        }


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

            Canvas.SetLeft(ellipseO, Opos.X - 15);
            Canvas.SetTop(ellipseO, Opos.Y - 15);

            if (AnalogCanvs.Children.Contains(ellipseO))
                AnalogCanvs.Children.Remove(ellipseO);
            AnalogCanvs.Children.Add(ellipseO);
        }

        /// <summary>
        /// 画圆表盘数字
        /// </summary>
        private void DrawDigit()
        {
            double x, y;
            for (int i = 1; i < 13; i++)
            {
                angle = WrapAngle(i * 360.0 / 12.0) - 90.0;
                angle = ConvertDegreesToRadians(angle);

                x = Opos.X + Math.Cos(angle) * (radius - 36) - 8;
                y = Opos.Y + Math.Sin(angle) * (radius - 36) - 15;

                TextBlock digit = new TextBlock();
                digit.FontSize = 26;
                digit.Text = i.ToString();

                // 数字12位置校正
                if (i == 12)
                {
                    Canvas.SetLeft(digit, x - 8);
                }
                else
                {
                    Canvas.SetLeft(digit, x);
                }
                Canvas.SetTop(digit, y);
                AnalogCanvs.Children.Add(digit);
            }
        }

        /// <summary>
        /// 画圆表刻度
        /// </summary>
        private void DrawGridLine()
        {
            double x1 = 0, y1 = 0;
            double x2 = 0, y2 = 0;

            for (int i = 0; i < 60; i++)
            {
                double angle1 = WrapAngle(i * 360.0 / 60.0) - 90;
                angle1 = ConvertDegreesToRadians(angle1);

                if (i % 5 == 0)
                {
                    x1 = Math.Cos(angle1) * (radius - 20);
                    y1 = Math.Sin(angle1) * (radius - 20);
                }
                else
                {
                    x1 = Math.Cos(angle1) * (radius - 10);
                    y1 = Math.Sin(angle1) * (radius - 10);
                }

                x2 = Math.Cos(angle1) * (radius - 5);
                y2 = Math.Sin(angle1) * (radius - 5);

                Line line = new Line();
                line.X1 = x1;
                line.Y1 = y1;
                line.X2 = x2;
                line.Y2 = y2;
                line.Stroke = Brushes.Black;
                line.StrokeThickness = 3;

                Canvas.SetLeft(line, Opos.X);
                Canvas.SetTop(line, Opos.Y);
                AnalogCanvs.Children.Add(line);

            }
        }

        /// <summary>
        /// 画时针
        /// </summary>
        private void DrawHourLine()
        {
            int hour = CurrTime.Hour;
            int minu = CurrTime.Minute;
            double dminu = minu / 60.0;         // 根据分钟数增加时针偏移
            double dhour = hour + dminu;

            double hour_angle = WrapAngle(dhour * (360.0 / 12.0) - 90.0);
            hour_angle = ConvertDegreesToRadians(hour_angle);

            double x = Math.Cos(hour_angle) * (radius - 100);
            double y = Math.Sin(hour_angle) * (radius - 100);

            HourLine.X1 = 0;
            HourLine.Y1 = 0;
            HourLine.X2 = x;
            HourLine.Y2 = y;
            HourLine.Stroke = Brushes.Black;
            HourLine.StrokeThickness = 4;

            Canvas.SetLeft(HourLine, Opos.X);
            Canvas.SetTop(HourLine, Opos.Y);
            if (AnalogCanvs.Children.Contains(HourLine))
            {
                AnalogCanvs.Children.Remove(HourLine);
            }
            AnalogCanvs.Children.Add(HourLine);
        }

        /// <summary>
        /// 画分针
        /// </summary>
        private void DrawMinuteLine()
        {
            int minu = CurrTime.Minute;
            int sec = CurrTime.Second;
            double dsec = sec / 60.0;         // 根据秒数增加时针偏移
            double dminu = minu + dsec;

            double minu_angle = WrapAngle(dminu * (360.0 / 60.0) - 90);
            minu_angle = ConvertDegreesToRadians(minu_angle);

            double x = Math.Cos(minu_angle) * (radius - 50);
            double y = Math.Sin(minu_angle) * (radius - 50);

            MinuLine.X1 = 0;
            MinuLine.Y1 = 0;
            MinuLine.X2 = x;
            MinuLine.Y2 = y;
            MinuLine.Stroke = Brushes.Yellow;
            MinuLine.StrokeThickness = 4;

            Canvas.SetLeft(MinuLine, Opos.X);
            Canvas.SetTop(MinuLine, Opos.Y);
            if (AnalogCanvs.Children.Contains(MinuLine))
            {
                AnalogCanvs.Children.Remove(MinuLine);
            }
            AnalogCanvs.Children.Add(MinuLine);
        }

        /// <summary>
        /// 画秒针
        /// </summary>
        private void DrawSecondLine()
        {
            int second = CurrTime.Second;

            // 秒针正方向点
            double se_angle = WrapAngle(second * (360.0 / 60.0) - 90);
            se_angle = ConvertDegreesToRadians(se_angle);
            double sec_x = Math.Cos(se_angle) * (radius - 40);
            double sec_y = Math.Sin(se_angle) * (radius - 40);

            // 秒针反方向点
            se_angle = WrapAngle(second * (360.0 / 60.0) + 90);
            se_angle = ConvertDegreesToRadians(se_angle);
            double sec_x_ = Math.Cos(se_angle) * (radius - 180);
            double sec_y_ = Math.Sin(se_angle) * (radius - 180);

            SecdLine.X1 = sec_x_;
            SecdLine.Y1 = sec_y_;
            SecdLine.X2 = sec_x;
            SecdLine.Y2 = sec_y;
            SecdLine.Stroke = Brushes.Red;
            SecdLine.StrokeThickness = 3;

            Canvas.SetLeft(SecdLine, Opos.X);
            Canvas.SetTop(SecdLine, Opos.Y);
            if (AnalogCanvs.Children.Contains(SecdLine))
            {
                AnalogCanvs.Children.Remove(SecdLine);
            }
            AnalogCanvs.Children.Add(SecdLine);
        }

        /// <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>
        private void Update()
        {
            DrawHourLine();
            DrawMinuteLine();
            DrawSecondLine();
            //DrawOCircle();
            //DrawNumerClock();
            numberClock.Content = DateTime.Now.ToString("HH:mm:ss");
        }

        /// <summary>
        /// 计时器事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            // 更新当前时间
            CurrTime = DateTime.Now;
            // 更新圆盘时针
            Update();
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值