Help us understand the problem. What is going on with this article?

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

はじめに

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でも公開しています。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした