본문 바로가기

C# WPF

Analog Clock in C# WPF(아날로그 시계) - 2

 C# WPF로 아래와 같은 아날로그 시계를 만든다.

시계바늘의 움직임은 다음의 식으로 계산된다. 삼각함수가 파라메터로 radian 값을 받기때문에 각도는 radian으로 변형해야 한다.

DateTime currentTime = new DateTime();

currentTime = DateTime.Now;

double radHr = (currentTime.Hour % 12 + currentTime.Minute / 60F) * 30 * Math.PI / 180;    // 시침은 1시간에 30도 + 1분에 0.5도
double radMin = (currentTime.Minute) * 6 * Math.PI / 180;    // 분침은 1분에 6도
double radSec = (currentTime.Second) * 6 * Math.PI / 180;    // 초침은 1초에 6도씩

DispatcherTimer 를 불러서 1초에 한번씩 각도를 계산하고 각 바늘의 좌표를 계산한다. DispatcherTimer를 사용하려면 using System.Windows.Threading; 을 써준다.

바늘의 좌표는 다음과 같이 계산한다. 

sin(θ) = x / Length à x = sin(θ) * L

cos(θ) = y / Length à y = cos(θ) * L

프로그램의 기본 구조는 다음과 같다. 1초에 한번씩 타이머가 dispatchTimer_Tick 이라는 함수를 불러준다. 이 함수에서 DrawClock()을 호출하여 시계를 그리게 된다. 

public MainWindow()

{

    InitializeComponent();

    dispatchTimer = new DispatcherTimer();

    dispatchTimer.Interval = new TimeSpan(0, 0, 1);

    dispatchTimer.Tick += dispatchTimer_Tick;

    dispatchTimer.Start();

}

 void dispatchTimer_Tick(object sender, object e)

 {

    DrawClock();

 }

 

 

전체 소스코드는 다음과 같다.

// 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="MyClock" Height="400" Width="340">

    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Canvas Name="Grid1" Margin="10">
            <Ellipse Name="Face" Width="300" Height="300" StrokeThickness="3" Stroke="#FFFCC07B"></Ellipse>
            <Ellipse Margin="145,145,0,0" Stroke="Chocolate" Fill="Chocolate" Width="10" Height="10" />
        </Canvas>
        <TextBlock Grid.Row="1" Margin="10" VerticalAlignment="Bottom" HorizontalAlignment="Center" Name="DTimer" FontSize="16" Foreground="#FF084108" FontFamily="Times New Roman" FontStyle="Normal"></TextBlock>
    </Grid>
</Window>

// CS 소스

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading; //Dispatcher

namespace AnalogClock
{
    public partial class MainWindow : Window
    {
        private double radius;
        private Point Center;
        private int hourHand;
        private int minHand;
        private int secHand;
        private DateTime currentTime;

        public MainWindow()
        {
            InitializeComponent();

            ClockSettng();

            DispatcherTimer Timer = new System.Windows.Threading.DispatcherTimer();
            Timer.Tick += new EventHandler(dispatcherTimer_Tick);
            Timer.Interval = new TimeSpan(0,0,1); // TimeSpan(0, 0, 1);
            Timer.Start();
        }

        private void ClockSettng()
        {
            Center = new Point(Face.Width / 2, Face.Height / 2);
            radius = Face.Width / 2;

            hourHand = (int)(radius * 0.6);
            minHand = (int)(radius * 0.8);
            secHand = (int)(radius * 0.9);
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            // 화면 지우고...
            Grid1.Children.Clear();

            currentTime = DateTime.Now;           
            DTimer.Text = DateTime.Now.ToString();
                        
            DrawClockFace();

            double radHr = (currentTime.Hour % 12 + currentTime.Minute / 60F) * 30 * Math.PI / 180;
            double radMin = (currentTime.Minute) * 6 * Math.PI / 180;
            double radSec = (currentTime.Second) * 6 * Math.PI / 180;
           
            DrawHands(radHr, radMin, radSec);
        }

        private void DrawLine(double x1, double y1, double x2, double y2, SolidColorBrush color, int thickness, Thickness margin)
        {
            Line line = new Line();
            line.X1 = x1; line.Y1 = y1; line.X2 = x2; line.Y2 = y2;
            line.Stroke = color;
            line.StrokeThickness = thickness;
            line.Margin = margin;
            Grid1.Children.Add(line);
        }

        private void DrawHands(double radHr, double radMin, double radSec)
        {
            // hour
            DrawLine(hourHand * Math.Sin(radHr), -hourHand * Math.Cos(radHr), 0, 0,
                Brushes.Green, 10, new Thickness(Center.X, Center.Y, 0, 0));

            // minute
            DrawLine(minHand * Math.Sin(radMin), -minHand * Math.Cos(radMin), 0, 0,
                Brushes.Blue, 8, new Thickness(Center.X, Center.Y, 0, 0));

            // second
            DrawLine(secHand * Math.Sin(radSec), -secHand * Math.Cos(radSec), 0, 0,
                Brushes.Red, 3, new Thickness(Center.X, Center.Y, 0, 0));

            // center : 중심점
            Ellipse center = new Ellipse();
            center.Margin = new Thickness(140, 140, 0, 0);
            center.Stroke = Brushes.Brown;
            center.StrokeThickness = 2;
            center.Fill = Brushes.Chocolate;
            center.Width = 20;
            center.Height = 20;
            Grid1.Children.Add(center);

        }

        private void DrawClockFace()
        {
            // 시계판 바깥 원
            Ellipse outer = new Ellipse();
            outer.Stroke = Brushes.Khaki;
            outer.StrokeThickness = 3;
            outer.Width = 300;
            outer.Height = 300;
            outer.Fill = Brushes.White;
            Grid1.Children.Add(outer);

            // 눈금
            int L;
            int strokeThickness;
            SolidColorBrush strokeColor;

            for (int deg = 0; deg < 360; deg += 6)
            {
                double rad = deg * Math.PI / 180;
                if (deg % 30 == 0)
                {
                    L = (int)(radius * 0.9);
                    strokeThickness = 5;
                    strokeColor = Brushes.Orange;
                }
                else
                {
                    L = (int)(radius * 0.95);
                    strokeThickness = 3;
                    strokeColor = Brushes.YellowGreen;
                }

                DrawLine(L * Math.Sin(rad), -L * Math.Cos(rad), (radius - 2) * Math.Sin(rad), -(radius - 2) * Math.Cos(rad),
                    strokeColor, strokeThickness, new Thickness(Center.X, Center.Y, 0, 0));
            }
                       
            DTimer.Text = DateTime.Now.ToString();
        }
    }
}

 

BeeEye 드무