LoginSignup
2
7

More than 3 years have passed since last update.

WPFのアニメーション機能を使い針を滑らかに動かすアナログ時計を作成する

Last updated at Posted at 2019-06-09

はじめに

WPFのDispatcherTimerクラスを使い簡易アナログ時計を作成する」でDispatcherTimerを使った簡易アナログ時計のサンプルコードを掲載しましたが、こちらは、WPFのアニメーション機能を使った簡易アナログ時計のサンプルです。

実行例

画像ではわかりませんが、秒針が滑らかに動きます。

2019-06-01 10_07_29.png

処理の概要

概要は以下のとおり。

  • 秒針、分針、時針の3つをLineオブジェクトとして表す。
  • 3つのLineオブジェクトの、RenderTransformプロパティには、RotateTransformを設定する。
  • 秒針、分針、時針に対応する Storyboard を定義する。
  • Storyboardでは、上記RotateTransformの回転角度を変化させることでそれぞれの針を動かす。
  • WindowのLoad時に、3つの針の角度を初期化し、アニメーションを開始する。

XAML

XAMLを示します。

Storyboardを3つ定義しているので、XAMLの行数が多めですが、ひとつひとつの要素はそれほど複雑ではありません。

<Window x:Class="WpfAnalogClock2.MainWindow"
        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:WpfAnalogClock2"
        mc:Ignorable="d"
        Title="Clock" Height="260" Width="260" 
        Loaded="Window_Loaded" >
    <Window.Resources>
        <Storyboard x:Key="SecondHand" x:Name="SecondHand" RepeatBehavior="Forever" >
            <DoubleAnimation
                Duration="0:1:0" From="0" To="360"
                Storyboard.TargetName="SecondLine"
                Storyboard.TargetProperty="(Line.RenderTransform).(RotateTransform.Angle)"
            />
        </Storyboard>
        <Storyboard x:Key="MinuteHand" x:Name="MinuteHand" RepeatBehavior="Forever">
            <DoubleAnimation
                Duration="1:0:0" From="0" To="360"
                Storyboard.TargetName="MinuteLine"
                Storyboard.TargetProperty="(Line.RenderTransform).(RotateTransform.Angle)"
            />
        </Storyboard>
        <Storyboard x:Key="HourHand" x:Name="HourHand" RepeatBehavior="Forever">
            <DoubleAnimation
                Duration="12:0:0" From="0" To="360"
                Storyboard.TargetName="HourLine"
                Storyboard.TargetProperty="(Line.RenderTransform).(RotateTransform.Angle)"
            />
        </Storyboard>
    </Window.Resources>
    <Canvas Width="200" Height="200">
        <Line x:Name="HourLine"  Stroke="Black" Fill="Black" 
              X1="100" Y1="100" X2="100" Y2="35"              
               StrokeThickness="3" >
            <Line.RenderTransform>
                <RotateTransform  x:Name="AngleHour" Angle="0" 
                                  CenterX="100" CenterY="100"/>
            </Line.RenderTransform>
        </Line>
        <Line x:Name="MinuteLine"  Stroke="Black" Fill="Black" 
              X1="100" Y1="100" X2="100" Y2="15"              
               StrokeThickness="2" >
            <Line.RenderTransform>
                <RotateTransform x:Name="AngleMinute"  Angle="0" 
                                 CenterX="100" CenterY="100"/>
            </Line.RenderTransform>
        </Line>
        <Line x:Name="SecondLine"  Stroke="Black" Fill="LightGray"
              X1="100" Y1="120" X2="100" Y2="10"  >
            <Line.RenderTransform>
                <RotateTransform x:Name="AngleSecond" Angle="0"  
                                 CenterX="100" CenterY="100"/>
            </Line.RenderTransform>
        </Line>
        <Ellipse Fill="Black" Width="6" Height="6" HorizontalAlignment="Center" 
                 VerticalAlignment="Center" 
                 Canvas.Top="97" Canvas.Left="97"/>
    </Canvas>
</Window>

C#のコード

C#側もいたって簡単なコードです。

現在の時刻に合せて、それぞれの針の初期の角度を設定し、これをFromの角度とし、Toはそれに360度を加えた角度とします。Durationは、XAMLで設定した値を使います。これでアニメーションをスタートさせています。

たったこっれだけで秒針が滑らかに動くアナログ時計が実現できるのはちょっとした驚きです。

using System;
using System.Windows;
using System.Windows.Media.Animation;

namespace WpfAnalogClock2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            InitializeAngle();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            StartAnimation("HourHand", this.AngleHour.Angle);
            StartAnimation("MinuteHand", this.AngleMinute.Angle);
            StartAnimation("SecondHand", this.AngleSecond.Angle);
        }

        void InitializeAngle()
        {
            DateTime dt = DateTime.Now;
            this.AngleSecond.Angle = dt.Second * 360.0 / 60.0;
            this.AngleMinute.Angle = (dt.Minute + dt.Second / 60.0) * 360.0 / 60.0;
            this.AngleHour.Angle = (dt.Hour + dt.Minute / 60.0) * 360.0 / 12;
        }

        private void StartAnimation(string name, double angle)
        {
            var sb = this.Resources[name] as Storyboard;
            var da = sb.Children[0] as DoubleAnimation;
            da.From = angle;
            da.To = da.From + 360.0;
            sb.Begin();
        }

    }
}

ソースコードは、GitHubでも公開しています。

2
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7