티스토리 뷰

VS-02분반수업

VP(22-06-10)

choimyeongheon 2022. 6. 18. 03:02

[1] WPF Clock

<Window x:Class="_041_WPFClock.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:_041_WPFClock"
        mc:Ignorable="d"
        Title="WPF Clock" Height="350" Width="350">
  <StackPanel>
    <Menu>
      <MenuItem Header="보기">
        <MenuItem Header="아날로그" Click="Analog_Clcik"/>
        <MenuItem Header="디지털" Click="Digital_Clcik"/>
        <Separator/>
        <MenuItem Header="종료" Click="Exit_Clcik"/>
      </MenuItem>
      <MenuItem Header="옵션">
        <MenuItem Header="초단 위" Click="Sec_Clcik"/>
        <MenuItem Header="밀리초 단위" Click="MSec_Clcik"/>
      </MenuItem>
    </Menu>
    <Grid Margin="10">
      <Canvas x:Name="canvas1" Width="250" Height="250">
        <Ellipse x:Name="aClock" Width="250" Height="250"/>
      </Canvas>
      <TextBlock x:Name="txtDate" 
                 FontFamily="맑은 고딕"
                 FontSize="15" Margin="15, 50"
                 Foreground="OrangeRed"/>
      <TextBlock x:Name="txtTime"
                 FontFamily="맑은 고딕"
                 FontSize="40"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center"
                 Foreground="RoyalBlue"/>
    </Grid>
  </StackPanel>
</Window>

<Xmal>

xmal에서는 메뉴들을 만들어주고 

그리드안에 canvas를 넣어 타원을 하나 생성해주었다.

그 후 텍스트블록을 두 개 넣어주었다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;

namespace _041_WPFClock
{
  /// <summary>
  /// MainWindow.xaml에 대한 상호 작용 논리
  /// </summary>
  public partial class MainWindow : Window
  {
    Point center;
    int radius;
    int hourHand;
    int minHand;
    int secHand;
    bool aFlag = true;  // true:아날로그 false:디지털
    bool msFlag = false; // false: 초단위 true:ms단위
    DispatcherTimer timer;
    public MainWindow()
    {
      InitializeComponent();

      aClockSetting();
      timerSetting();
    }

    private void timerSetting()
    {
      timer = new DispatcherTimer();
      timer.Interval = new TimeSpan(0, 0, 0, 1); // 10밀리초
      timer.Tick += Timer_Tick;
      timer.Start();
    }

    private void Timer_Tick(object sender, EventArgs e)
    {
      DateTime c = DateTime.Now;

      canvas1.Children.Clear();

      if (aFlag == true)   // 아날로그 시계
      {
        DrawClockFace();  // 시계판 그리기

        // 시간에 따라 시계바늘을 그린다
        // 시침, 분침, 초침의 각도 구하기
        double degHr = (c.Hour % 12) * 30 + c.Minute * 0.5;
        double degMin = c.Minute * 6 + c.Second * 0.1;
        double degSec = c.Second * 6 + c.Millisecond * 6.0 / 1000;
        //double degSec;
        //if (msFlag == true)
        //  degSec =
        //    c.Second * 6 + c.Millisecond * 6.0 / 1000;
        //else
        //  degSec = c.Second * 6;

        // 라디안으로 변화
        double radHr = Math.PI * degHr / 180;
        double radMin = Math.PI * degMin / 180;
        double radSec = Math.PI * degSec / 180;

        DrawHands(radHr, radMin, radSec);
      } 
      else // 디지털 시계
      {
        txtDate.Text = DateTime.Today.ToString("D");
        if(msFlag == false) // 초단위
          txtTime.Text = String.Format(
            "{0:D2}:{1:D2}:{2:D2}",
            c.Hour, c.Minute, c.Second);
        else // 밀리초 단위
          txtTime.Text = String.Format(
            "{0:D2}:{1:D2}:{2:D2}.{3:D3}",
            c.Hour, c.Minute, c.Second, c.Millisecond);
      }
    }

    private void DrawHands(double radHr, double radMin, double radSec)
    {
      // 시침
      DrawLine(
        (int)(hourHand * Math.Sin(radHr)),
        (int)(-hourHand * Math.Cos(radHr)), 0, 0,
        Brushes.RoyalBlue, 12, center.X, center.Y);
      // 분침
      DrawLine(
        (int)(minHand * Math.Sin(radMin)),
        (int)(-minHand * Math.Cos(radMin)), 0, 0,
        Brushes.SkyBlue, 8, center.X, center.Y);
      // 초침
      DrawLine(
        (int)(secHand * Math.Sin(radSec)),
        (int)(-secHand * Math.Cos(radSec)), 0, 0,
        Brushes.OrangeRed, 5, center.X, center.Y);

      // 배꼽

      //Rectangle r = new Rectangle(
      //  center.X - coreSize / 2, center.Y - coreSize / 2,
      //  coreSize, coreSize);
      //g.FillEllipse(Brushes.Gold, r);
      //Pen p = new Pen(Brushes.DarkRed, 3);
      //g.DrawEllipse(p, r);

      int coreSize = 16;
      Ellipse core = new Ellipse();
      core.Margin = new Thickness(
        center.X - coreSize / 2, center.Y - coreSize / 2, 
        0, 0);
      core.Stroke = Brushes.DarkRed;
      core.StrokeThickness = 3;
      core.Fill = Brushes.Gold;
      core.Width = coreSize;
      core.Height = coreSize;
      canvas1.Children.Add(core);
    }

    private void DrawLine(int x1, int y1, int x2, int y2,
      Brush color, int thick, double Cx, double Cy)
    {
      Line line = new Line();
      line.X1 = x1;
      line.Y1 = y1;
      line.X2 = x2;
      line.Y2 = y2;
      line.Stroke = color;
      line.StrokeThickness = thick;
      line.Margin = new Thickness(Cx, Cy, 0,0);
      line.StrokeStartLineCap = PenLineCap.Round;
      canvas1.Children.Add(line);
    }

    private void DrawClockFace()
    {
      aClock.Stroke = Brushes.LightSteelBlue;
      aClock.StrokeThickness = 30;
      canvas1.Children.Add(aClock);
    }

    private void aClockSetting()
    {
      center = new Point(canvas1.Width/2, 
        canvas1.Height / 2);
      radius = (int)canvas1.Width / 2;
      hourHand = (int)(radius * 0.45);
      minHand = (int)(radius * 0.55);
      secHand = (int)(radius * 0.65);
    }

    private void Analog_Clcik(object sender, RoutedEventArgs e)
    {
      aFlag = true;
      txtDate.Text = "";
      txtTime.Text = "";
    }

    private void Digital_Clcik(object sender, RoutedEventArgs e)
    {
      aFlag = false;
    }

    private void Exit_Clcik(object sender, RoutedEventArgs e)
    {
      this.Close();
    }

    private void Sec_Clcik(object sender, RoutedEventArgs e)
    {
      msFlag = false;
      timer.Interval = new TimeSpan(0, 0, 0, 1);// 1초
      
    }

    private void MSec_Clcik(object sender, RoutedEventArgs e)
    {
      msFlag = true;
      timer.Interval = new TimeSpan(0, 0, 0, 0, 10); // 0.01초
    }
  }
}

전체 cs코드이다.

Point center;
    int radius;
    int hourHand;
    int minHand;
    int secHand;
    bool aFlag = true;  // true:아날로그 false:디지털
    bool msFlag = false; // false: 초단위 true:ms단위
    DispatcherTimer timer;

전역변수로는 Point타입의 center와

반지름,시침,분침,초침을 Int형으로 

bool타입 flag를 두 개 

timer를 하나 선언해주었다.

public MainWindow()
    {
      InitializeComponent();

      aClockSetting();
      timerSetting();
    }

윈도우 호출에서는

aClockSetting함수와 timerSetting을 실행해주었다.

private void timerSetting()
    {
      timer = new DispatcherTimer();
      timer.Interval = new TimeSpan(0, 0, 0, 1); // 10밀리초
      timer.Tick += Timer_Tick;
      timer.Start();
    }

위에 선언한 timerSetting함수이다.

timer를 함수로 한번에 설정해주는 작업이다.

타이머를 초기화해준 뒤 인터벌과 

Dispatchtimer에서는 timespan으로 설정해준다.

Tick이벤트핸들러를 선언해준다.

타이머를 실행해준다.

private void Timer_Tick(object sender, EventArgs e)
    {
      DateTime c = DateTime.Now;

      canvas1.Children.Clear();

      if (aFlag == true)  
      {
        DrawClockFace(); 

        double degHr = (c.Hour % 12) * 30 + c.Minute * 0.5;
        double degMin = c.Minute * 6 + c.Second * 0.1;
        double degSec = c.Second * 6 + c.Millisecond * 6.0 / 1000;
        double radHr = Math.PI * degHr / 180;
        double radMin = Math.PI * degMin / 180;
        double radSec = Math.PI * degSec / 180;

        DrawHands(radHr, radMin, radSec);
      } 
      else 
      {
        txtDate.Text = DateTime.Today.ToString("D");
        if(msFlag == false) 
          txtTime.Text = String.Format(
            "{0:D2}:{1:D2}:{2:D2}",
            c.Hour, c.Minute, c.Second);
        else // 밀리초 단위
          txtTime.Text = String.Format(
            "{0:D2}:{1:D2}:{2:D2}.{3:D3}",
            c.Hour, c.Minute, c.Second, c.Millisecond);
      }
    }

DateTime class c를 선언하여 현재시간으로 설정해준다.

canvas의 child를 clear해준다.

침들의 자취가 남는것을 방지하기 위해서 진행해준다.

if (aFlag == true)  
      {
        DrawClockFace(); 

        double degHr = (c.Hour % 12) * 30 + c.Minute * 0.5;
        double degMin = c.Minute * 6 + c.Second * 0.1;
        double degSec = c.Second * 6 + c.Millisecond * 6.0 / 1000;
        double radHr = Math.PI * degHr / 180;
        double radMin = Math.PI * degMin / 180;
        double radSec = Math.PI * degSec / 180;

        DrawHands(radHr, radMin, radSec);
      }

aFlag가 true라면 실행한다.

각도를 계산해주어 radian값으로 변환해준다.

다음 Drawhand함수를 선언하여 값들을 넣어 침들을 그려준다.

else 
      {
        txtDate.Text = DateTime.Today.ToString("D");
        if(msFlag == false) 
          txtTime.Text = String.Format(
            "{0:D2}:{1:D2}:{2:D2}",
            c.Hour, c.Minute, c.Second);
        else // 밀리초 단위
          txtTime.Text = String.Format(
            "{0:D2}:{1:D2}:{2:D2}.{3:D3}",
            c.Hour, c.Minute, c.Second, c.Millisecond);
      }

aFlag가 false라면 디지털 시계를 출력해준다.

ToString("D")는 Demical 정수형으로 표시하라는 뜻이다.

msFlag가 false라면 시 분 초만 표시해준다.

아니라면 밀리초단위로 표시해준다.

private void DrawHands(double radHr, double radMin, double radSec)
    {
      // 시침
      DrawLine(
        (int)(hourHand * Math.Sin(radHr)),
        (int)(-hourHand * Math.Cos(radHr)), 0, 0,
        Brushes.RoyalBlue, 12, center.X, center.Y);
      // 분침
      DrawLine(
        (int)(minHand * Math.Sin(radMin)),
        (int)(-minHand * Math.Cos(radMin)), 0, 0,
        Brushes.SkyBlue, 8, center.X, center.Y);
      // 초침
      DrawLine(
        (int)(secHand * Math.Sin(radSec)),
        (int)(-secHand * Math.Cos(radSec)), 0, 0,
        Brushes.OrangeRed, 5, center.X, center.Y);

      int coreSize = 16;
      Ellipse core = new Ellipse();
      core.Margin = new Thickness(
        center.X - coreSize / 2, center.Y - coreSize / 2, 
        0, 0);
      core.Stroke = Brushes.DarkRed;
      core.StrokeThickness = 3;
      core.Fill = Brushes.Gold;
      core.Width = coreSize;
      core.Height = coreSize;
      canvas1.Children.Add(core);
    }

DrawHand함수를 사용하여 침들을 그려주었다.

추후에 코딩해줄 DrawLine함수를 사용하여 선을 그려주었다.

sin , cos값과 0,0 색상과 두께 그리고 센터값을 인자로 넘겨주었다.

int형 coresize를 16으로지정해준다.

ellipse클래스의 core를 선언하여 새 타원을 선언해준다.

p1,p2의 좌표와 p3,p4를 꼭짓점으로하는 사각형을 생성해주어 안에 원을 그려주는 방식이다.

core의 색상과 두께 그리고 속색상과 width , height값을 설정해주고 canvas에 children으로 넣어준다.

private void DrawLine(int x1, int y1, int x2, int y2,
      Brush color, int thick, double Cx, double Cy)
    {
      Line line = new Line();
      line.X1 = x1;
      line.Y1 = y1;
      line.X2 = x2;
      line.Y2 = y2;
      line.Stroke = color;
      line.StrokeThickness = thick;
      line.Margin = new Thickness(Cx, Cy, 0,0);
      line.StrokeStartLineCap = PenLineCap.Round;
      canvas1.Children.Add(line);
    }

DrawLine의 함수 구현부이다(x1,y1) 부터 (x2,y2)까지 선을 정해준 색상과 굵기로 그려주는데

margin으로 빈 사각형을 만들어 띄워준다(원하는 위치에서 시작하기 위한 과정)

linecap은 둥글게하여 선이 매끄럽게 나타나도록 해준다.

그 후 Line을 canvas에 children으로 넣어준다.

private void DrawClockFace()
    {
      aClock.Stroke = Brushes.LightSteelBlue;
      aClock.StrokeThickness = 30;
      canvas1.Children.Add(aClock);
    }

    private void aClockSetting()
    {
      center = new Point(canvas1.Width/2, 
        canvas1.Height / 2);
      radius = (int)canvas1.Width / 2;
      hourHand = (int)(radius * 0.45);
      minHand = (int)(radius * 0.55);
      secHand = (int)(radius * 0.65);
    }

시계의 판을 그려주는 DrawClockFace함수와 center와 시침,분침,초침의 길이를 설정해준다.

private void Analog_Clcik(object sender, RoutedEventArgs e)
    {
      aFlag = true;
      txtDate.Text = "";
      txtTime.Text = "";
    }

    private void Digital_Clcik(object sender, RoutedEventArgs e)
    {
      aFlag = false;
    }

    private void Exit_Clcik(object sender, RoutedEventArgs e)
    {
      this.Close();
    }

    private void Sec_Clcik(object sender, RoutedEventArgs e)
    {
      msFlag = false;
      timer.Interval = new TimeSpan(0, 0, 0, 1);// 1초
      
    }

    private void MSec_Clcik(object sender, RoutedEventArgs e)
    {
      msFlag = true;
      timer.Interval = new TimeSpan(0, 0, 0, 0, 10); // 0.01초
    }
  }
}

다음으로 analogClock을 표시할 함수와

반대로 디지털시계를 표시할 함수

그리고 종료함수와

초단위표시 메뉴설정 함수와

밀리초단위 설정함수를 설정해준다.

 

이후 실행하면

 

잘 실행된다.

 

감사합니다.

'VS-02분반수업' 카테고리의 다른 글

VP(22-06-15)  (0) 2022.06.18
VP(22-06-08)  (0) 2022.06.09
VP(22-06-03)  (0) 2022.06.08
VP(22-06-02)  (0) 2022.06.08
VP(22-05-27)  (0) 2022.05.30
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함