WPF实现钟表效果

下面我会为你详细讲解“WPF实现钟表效果”的完整攻略。

一、准备工作

1. 新建WPF应用程序

首先,我们需要新建一个WPF应用程序。

2. 引用PresentationCore、PresentationFramework、WindowsBase三个文件

在新建的WPF应用程序中,我们需要添加 PresentationCore、PresentationFramework、WindowsBase三个引用。

在Visual Studio的“解决方案资源管理器”中,右击“引用”,选择“添加引用”,接着在“程序集”选项卡中勾选 PresentationCore、PresentationFramework、WindowsBase这三个文件,然后点击“确定”按钮,即可完成引用。

3. 编写XAML代码

接下来,我们需要编写XAML代码,创建界面,并声明使用的命名空间。

<Window x:Class="ClockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Clock Demo" Height="150" Width="150">
    <Grid>
        <Ellipse Stroke="Gray" StrokeThickness="2" Width="100" Height="100"
                 VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
        <Line X1="50" Y1="50" X2="50" Y2="10" Stroke="Gray" StrokeThickness="2">
            <Line.RenderTransform>
                <RotateTransform x:Name="hourPointerTransform" CenterX="50" CenterY="50"/>
            </Line.RenderTransform>
        </Line>
        <Line X1="50" Y1="50" X2="50" Y2="5" Stroke="Gray" StrokeThickness="2">
            <Line.RenderTransform>
                <RotateTransform x:Name="minutePointerTransform" CenterX="50" CenterY="50"/>
            </Line.RenderTransform>
        </Line>
        <Line X1="50" Y1="50" X2="50" Y2="0" Stroke="Red" StrokeThickness="1">
            <Line.RenderTransform>
                <RotateTransform x:Name="secondPointerTransform" CenterX="50" CenterY="50"/>
            </Line.RenderTransform>
        </Line>
    </Grid>
</Window>

二、实现时钟功能

1. 计时器

我们需要定义一个计时器,并在计时器的Tick事件中更新表针指向。

public partial class MainWindow : Window
{
    private DispatcherTimer _timer;

    public MainWindow()
    {
        InitializeComponent();
        StartTimer();
    }

    public void StartTimer()
    {
        _timer = new DispatcherTimer();
        _timer.Interval = TimeSpan.FromSeconds(1);
        _timer.Tick += _timer_Tick;
        _timer.Start();
    }

    private void _timer_Tick(object sender, EventArgs e)
    {
        var now = DateTime.Now;
        hourPointerTransform.Angle = now.Hour * 30 + now.Minute * 0.5;
        minutePointerTransform.Angle = now.Minute * 6;
        secondPointerTransform.Angle = now.Second * 6;
    }
}

在MainWindow的构造函数中,我们调用了StartTimer方法启动计时器。在计时器的Tick事件中,我们首先获取当前时间,然后将时针、分针、秒针的角度更新为当前时间对应的角度。

2. 模拟渐变色效果

我们为秒针增加一个“闪烁”的效果,模拟出一个渐变色的效果。

private void _timer_Tick(object sender, EventArgs e)
{
    var now = DateTime.Now;
    hourPointerTransform.Angle = now.Hour * 30 + now.Minute * 0.5;
    minutePointerTransform.Angle = now.Minute * 6;

    if (now.Second == 0)
    {
        // 重置秒针的“闪烁”效果,以模拟渐变色的效果
        secondPointerTransform.BeginAnimation(RotateTransform.AngleProperty,
            new DoubleAnimation(now.Second * 6, (now.Second + 1) * 6, TimeSpan.FromSeconds(1)));
    }
    else
    {
        secondPointerTransform.Angle = now.Second * 6;
    }
}

在计时器的Tick事件中,当秒数等于0时,我们重置秒针的“闪烁”效果,以模拟出渐变色的效果。

三、示例说明

示例1

我们定义一个ZodiacClock控件,使用ZodiacClock实现一个12生肖的钟表。

<UserControl x:Class="ClockDemo.ZodiacClock"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Border Background="White" BorderBrush="Gray" BorderThickness="2" CornerRadius="150">
            <Grid>
                <Ellipse HorizontalAlignment="Center" VerticalAlignment="Center" Fill="White" Width="130" Height="130"/>
                <Ellipse HorizontalAlignment="Center" VerticalAlignment="Center" Fill="Gray" Width="120" Height="120"/>
                <Canvas>
                    <Path Data="M0,-130 A130,130 0 0,1 0,130" Stroke="Gray" StrokeThickness="4">
                        <Path.RenderTransform>
                            <RotateTransform Angle="{Binding ZodiacAngle}" CenterX="0" CenterY="0" />
                        </Path.RenderTransform>
                    </Path>
                    <Ellipse Width="20" Height="20" Stroke="Gray" StrokeThickness="2" Fill="White">
                        <Ellipse.RenderTransform>
                            <TranslateTransform X="-10" Y="{Binding YOffset}" />
                        </Ellipse.RenderTransform>
                    </Ellipse>
                </Canvas>
            </Grid>
        </Border>
        <StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center">
            <TextBlock Text="生肖" Margin="5,0,5,0"/>
            <ComboBox ItemsSource="{Binding ZodiacList}" DisplayMemberPath="Name" SelectedValuePath="Angle" SelectedValue="{Binding ZodiacAngle}"/>
        </StackPanel>
    </Grid>
</UserControl>
public class Zodiac
{
    public string Name { get; set; }
    public double Angle { get; set; }
}

public partial class ZodiacClock : UserControl
{
    public static readonly DependencyProperty ZodiacAngleProperty =
        DependencyProperty.Register("ZodiacAngle", typeof(double), typeof(ZodiacClock), new FrameworkPropertyMetadata(0d));

    public static readonly DependencyProperty YOffsetProperty =
        DependencyProperty.Register("YOffset", typeof(double), typeof(ZodiacClock), new FrameworkPropertyMetadata(0d));

    public static readonly DependencyProperty ZodiacListProperty =
        DependencyProperty.Register("ZodiacList", typeof(List<Zodiac>), typeof(ZodiacClock), new FrameworkPropertyMetadata(null));

    public double ZodiacAngle
    {
        get { return (double)GetValue(ZodiacAngleProperty); }
        set { SetValue(ZodiacAngleProperty, value); }
    }

    public double YOffset
    {
        get { return (double)GetValue(YOffsetProperty); }
        set { SetValue(YOffsetProperty, value); }
    }

    public List<Zodiac> ZodiacList
    {
        get { return (List<Zodiac>)GetValue(ZodiacListProperty); }
        set { SetValue(ZodiacListProperty, value); }
    }

    public ZodiacClock()
    {
        InitializeComponent();
        DataContext = this;

        ZodiacList = new List<Zodiac>
        {
            new Zodiac{Name="鼠", Angle=30},
            new Zodiac{Name="牛", Angle=60},
            new Zodiac{Name="虎", Angle=90},
            new Zodiac{Name="兔", Angle=120},
            new Zodiac{Name="龙", Angle=150},
            new Zodiac{Name="蛇", Angle=180},
            new Zodiac{Name="马", Angle=210},
            new Zodiac{Name="羊", Angle=240},
            new Zodiac{Name="猴", Angle=270},
            new Zodiac{Name="鸡", Angle=300},
            new Zodiac{Name="狗", Angle=330},
            new Zodiac{Name="猪", Angle=0}
        };

        var timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += timer_Tick;

        Loaded += (s, e) => timer.Start();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        var now = DateTime.Now;
        var remainder = now.Second % 5;
        YOffset = remainder < 3 ? 10 * remainder : 20 - 10 * remainder;
    }
}

我们新建了一个叫ZodiacClock的UserControl,里面定义了一个“生肖钟表”的控件。在该控件中,我们通过绑定ZodiacAngle和YOffset的值,来定位当时的生肖,并同时通过timer的Tick事件来实现一个微小的晃动效果。

示例2

我们定义一个GreenClock控件,使用GreenClock实现一个环保时钟,并在时钟上显示环保提示语。

<UserControl x:Class="ClockDemo.GreenClock"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <Style x:Key="NumTextStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Foreground" Value="#FF00703C"/>
            <Setter Property="Margin" Value="5"/>
        </Style>
    </UserControl.Resources>
    <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
        <Canvas Width="150" Height="150">
            <Ellipse Fill="#FF00703C" Width="150" Height="150"/>
            <Ellipse Fill="White" Width="130" Height="130" Canvas.Left="10" Canvas.Top="10"/>
            <TextBlock Text="环保提醒:"
                       Foreground="#FF00703C" Margin="0,0,0,10"
                       HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
            <TextBlock x:Name="tbReminder" Text="记得关灯、节水哦"
                       Style="{StaticResource NumTextStyle}"
                       Canvas.Left="10" Canvas.Top="10"/>
            <TextBlock x:Name="tbHour" Text="12" Style="{StaticResource NumTextStyle}">
                <TextBlock.RenderTransform>
                    <TranslateTransform X="-10" Y="-60"/>
                </TextBlock.RenderTransform>
            </TextBlock>
            <TextBlock x:Name="tbMinute" Text="00" Style="{StaticResource NumTextStyle}">
                <TextBlock.RenderTransform>
                    <TranslateTransform X="-7" Y="-35"/>
                </TextBlock.RenderTransform>
            </TextBlock>
            <TextBlock x:Name="tbSecond" Text="00" Style="{StaticResource NumTextStyle}">
                <TextBlock.RenderTransform>
                    <TranslateTransform X="-3" Y="-15"/>
                </TextBlock.RenderTransform>
            </TextBlock>
            <Line Stroke="White" StrokeThickness="1" X1="10" Y1="10" X2="10" Y2="35">
                <Line.RenderTransform>
                    <RotateTransform x:Name="hourPointer" CenterX="10" CenterY="75"/>
                </Line.RenderTransform>
            </Line>
            <Line Stroke="White" StrokeThickness="1" X1="10" Y1="10" X2="10" Y2="50">
                <Line.RenderTransform>
                    <RotateTransform x:Name="minutePointer" CenterX="10" CenterY="75"/>
                </Line.RenderTransform>
            </Line>
            <Line Stroke="White" StrokeThickness="1" X1="10" Y1="10" X2="10" Y2="60">
                <Line.RenderTransform>
                    <RotateTransform x:Name="secondPointer" CenterX="10" CenterY="75"/>
                </Line.RenderTransform>
            </Line>
        </Canvas>
    </StackPanel>
</UserControl>
public partial class GreenClock : UserControl
{
    private string[] _reminderList = new string[] 
    {
        "记得关灯、节水哦", "保护环境,从我做起", "为了我们的地球", "要低碳,不要空气污染", "替代传统能源", "再创绿色奇迹"
    };

    public GreenClock()
    {
        InitializeComponent();

        Loaded += (s, e) =>
        {
            var timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += timer_Tick;
            timer.Start();

            tbReminder.Text = _reminderList[new Random((int)DateTime.Now.Ticks).Next(0, _reminderList.Length)];
        };
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        var now = DateTime.Now;
        hourPointer.Angle = now.Hour * 30 + now.Minute * 0.5;
        minutePointer.Angle = now.Minute * 6;
        secondPointer.Angle = now.Second * 6;

        if (now.Second == 0)
        {
            tbReminder.Text = _reminderList[new Random((int)DateTime.Now.Ticks).Next(0, _reminderList.Length)];
        }

        tbHour.Text = now.Hour.ToString().PadLeft(2, '0');
        tbMinute.Text = now.Minute.ToString().PadLeft(2, '0');
        tbSecond.Text = now.Second.ToString().PadLeft(2, '0');
    }
}

我们新建了一个叫GreenClock的UserControl,里面定义了一个“环保时钟”的控件。在该控件中,我们通过绑定hourPointer、minutePointer和secondPointer的旋转角度实现指针的动态更新,并通过timer的Tick事件来实现每秒更新时间和随机显示绿色环保提示语。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:WPF实现钟表效果 - Python技术站

(0)
上一篇 2023年6月1日
下一篇 2023年6月1日

相关文章

  • c#实现16进制和字符串之间转换的代码

    下面是详细讲解C#实现16进制和字符串之间转换的完整攻略。 背景介绍 在计算机科学中,十六进制是一种更方便地表示二进制数的方法,而字符串则是日常编程中常见的一种数据类型。在实际开发中,我们经常会需要将十六进制和字符串之间进行转换,以方便进行数据传输或处理。 策略分析 在C#中,我们可以通过以下两种方式实现十六进制和字符串之间的转换: 使用BitConvert…

    C# 2023年6月6日
    00
  • C#先判断是否存在再创建文件夹或文件与递归计算文件夹大小

    下面是关于“C#先判断是否存在再创建文件夹或文件与递归计算文件夹大小”的详细攻略。 1. 先判断是否存在再创建文件夹或文件 在C#中,我们可以使用System.IO.Directory和System.IO.File类来创建文件夹或文件,并且可以通过相应的方法,判断是否存在。 1.1 判断文件夹是否存在并创建文件夹 如果我们需要判断一个文件夹是否存在,并在不存…

    C# 2023年5月15日
    00
  • C# Stream.ReadByte – 从流中读取一个字节

    C# 中的 Stream 类提供了许多方法来读取和写入字节流,其中包括 ReadByte 方法。ReadByte 方法的作用是从当前流中读取下一个字节并提升流的位置一个字节,如果流已经结束,则返回 -1。 使用方法的完整攻略如下: 语法 public virtual int ReadByte(); 返回值 返回读取的字节的整数表示形式,如果已经读取到流的末尾…

    C# 2023年4月19日
    00
  • C# String.Concat()方法: 连接两个或多个字符串

    C#中的String.Concat()方法可以将一个或多个字符串连接到一起,并返回一个新的字符串。对于每个传递给方法的参数,字符串都会被复制到新字符串中。这个方法是静态方法,可以使用类名来调用,其语法如下: string.Concat(string str0, string str1, …, string strN) 其中,str0、str1…strN是…

    C# 2023年4月19日
    00
  • C# Linq的OrderBy()方法 – 根据指定的键按升序对序列的元素进行排序

    C#中的Linq提供了一种方便的方法来处理数据序列,其中OrderBy()是排序操作中的一个重要部分。OrderBy()方法可以按照序列中指定的键值对序列进行排序,并返回一个IEnumerable类型的序列。 语法格式 public static IOrderedEnumerable<TSource> OrderBy<TSource, TK…

    C# 2023年4月19日
    00
  • Blazor UI库 Bootstrap Blazor 快速上手 (v7.5.7)

    最近组件库更新比较频繁,有些同学感觉有点迷茫,就着今天刚上了张老板一节课立马撸个新的上手教程回馈社区, ;-> 1.新建工程b18QuickStartv757,将项目添加到解决方案中 dotnet new blazorserver -o b18QuickStartv757 dotnet sln add b18QuickStartv757/b18Quic…

    C# 2023年5月4日
    00
  • ASP.NET Core MVC通过IActionFilter.OnActionExecuting方法,获取Controller的Action方法参数值

    用过ASP.NET Core MVC中IActionFilter拦截器的开发人员,都知道这是一个非常强大的MVC拦截器。最近才发现IActionFilter的OnActionExecuting方法,甚至可以获取Controller的Action方法参数值。 假如我们在ASP.NET Core MVC项目中有一个HomeController,其中有一个Acti…

    C# 2023年4月24日
    00
  • 详解c# AutoMapper 使用方式

    详解c# AutoMapper 使用方式 什么是AutoMapper? AutoMapper是一个C#库,用于对象之间的映射(mapping)。当我们需要将一个对象(Source)的属性值映射到另一个对象(Target)时,AutoMapper可以帮助我们快速而简便地完成这项工作,而无需手动写出大量的赋值表达式。 安装AutoMapper 可以通过NuGet…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部