×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。

WPF:アナログ時計 (アニメーション機能を使い秒針を滑らかに動かす例)    

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

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

 概要は以下のとおり。

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

XAMLを示します。

<Window x:Class="AnalogClock.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" 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>


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


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

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


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

namespace AnalogClock {
    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();
        }
    }  
}