티스토리 뷰

VS-02분반수업

VP(22-06-08)

choimyeongheon 2022. 6. 9. 19:22

[1]아날로그 시계

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace _040_FormClock
{
  public partial class Form1 : Form
  {
    // 필드, 속성
    Graphics g;
    bool aClock_Flag = true;
    Point center; // 중심점
    double radius;  // 반지름
    int hourHand;   // 시침의 길이
    int minHand;    // 분침
    int secHand;    // 초침
    
    const int clientSize = 300;
    const int clockSize = 200;

    public Form1()
    {
      InitializeComponent();

      this.ClientSize 
        = new Size(clientSize, clientSize+menuStrip1.Height);
      this.Text = "Form Clock";
      panel1.BackColor = Color.WhiteSmoke;

      g = panel1.CreateGraphics();
      aClockSetting();
      TimerSetting();
    }

    private void TimerSetting()
    {
      Timer timer = new Timer();
      timer.Interval = 1000;
      timer.Tick += Timer_Tick;
      timer.Start();
    }

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

      panel1.Refresh(); // 패널을 지운다
      DrawClockFace();  // 시계판

      // 시계바늘 그리기
      double radHr 
        = (c.Hour % 12 + c.Minute / 60.0) * 30 *Math.PI/180;
      double radMin 
        = (c.Minute + c.Second / 60.0) * 6 * Math.PI / 180;
      double radSec
        = c.Second * 6 * Math.PI / 180;

      DrawHands(radHr, radMin, radSec);
    }

    // 시계바늘 그리는 메소드
    private void DrawHands(double radHr, double radMin, double radSec)
    {
      // 시침(현재 시간의 좌표를 각도를 이용하여 구하자)
      DrawLine(0, 0,
        (int)(hourHand * Math.Sin(radHr)),
        (int)(hourHand * Math.Cos(radHr)),
        Brushes.RoyalBlue, 8);

      // 분침(현재 시간의 좌표를 각도를 이용하여 구하자)
      DrawLine(0, 0,
        (int)(minHand * Math.Sin(radMin)),
        (int)(minHand * Math.Cos(radMin)),
        Brushes.SkyBlue, 6);

      // 초침(현재 시간의 좌표를 각도를 이용하여 구하자)
      DrawLine(0, 0,
        (int)(secHand * Math.Sin(radSec)), 
        (int)(secHand * Math.Cos(radSec)),
        Brushes.OrangeRed, 4);

      // 배꼽
      int coreSize = 16;
      Rectangle r = new Rectangle(
        center.X - coreSize / 2, center.Y - coreSize / 2,
        coreSize, coreSize);
      g.FillEllipse(Brushes.Gold, r);
      g.DrawEllipse(new Pen(Brushes.Green, 3), r);
    }

    private void DrawLine(int x1, int y1, int x2, int y2,
      Brush brush, int thick)
    {
      Pen p = new Pen(brush, thick);
      p.EndCap = System.Drawing.Drawing2D.LineCap.Round;
      g.DrawLine(p, center.X + x1, center.Y + y1, 
        center.X + x2, center.Y - y2);
    }

    private void DrawClockFace()
    {
      Pen p = new Pen(Brushes.LightSteelBlue, 30);
      g.DrawEllipse(p,
        center.X - clockSize / 2,
        center.Y - clockSize / 2,
        clockSize,
        clockSize);
    }

    // 아날로그 시계 세팅
    private void aClockSetting()
    {
      center 
        = new Point(clientSize / 2, clientSize / 2);
      radius = clockSize / 2;

      hourHand = (int)(radius * 0.45);
      minHand = (int)(radius * 0.55);
      secHand = (int)(radius * 0.65);
    }
  }
}

저번주에 만들었던 것에 내용을 추가해준다.

const int clientSize = 300;
    const int clockSize = 200;

전역변수에 clientSize와 clockSize를 추가해준다.

this.ClientSize 
        = new Size(clientSize, clientSize+menuStrip1.Height);
panel1.BackColor = Color.WhiteSmoke;

clientSize를 너비는 clientSize(300)으로 높이는 clientSize+menu의 높이로 해준다.

panel의 배경색을 whitesmoke로 변경해준다.

panel1.Refresh(); // 패널을 지운다
double radHr 
        = (c.Hour % 12 + c.Minute / 60.0) * 30 *Math.PI/180;
      double radMin 
        = (c.Minute + c.Second / 60.0) * 6 * Math.PI / 180;
      double radSec
        = c.Second * 6 * Math.PI / 180;

      DrawHands(radHr, radMin, radSec);

다음은 T_Tick함수 내부의 코드이다.

처음부분에 panel을 초기화해준다.

이 과정이 없으면 초침의 흔적이 계속하여 남게된다.

저번주와 다르게 한번에 라디안값까지 계산해주었다.

그 후 DrawHands함수를 사용하여 바늘들을 패널에 그려주었다.

private void DrawLine(int x1, int y1, int x2, int y2,
      Brush brush, int thick)
    {
      Pen p = new Pen(brush, thick);
      p.EndCap = System.Drawing.Drawing2D.LineCap.Round;
      g.DrawLine(p, center.X + x1, center.Y + y1, 
        center.X + x2, center.Y - y2);
    }

새로 추가된 DrawLine함수이다

x1,y1,x2,y2,Brush,thick을 인자로 받는다

전체적인 내용은 x1,y1의 좌표로부터 x2,y2까지 brush의 색상을 갖는 굵기가 thick인 함수이다.

Pen class의 p를 brush와 thick을 매개변수로 삼아 선언해준 뒤

p의 endcap(선의형태)를 round(매끄럽고 둥그런 선)

그 밑줄에 쓰인 g.DrawLine은 현재 만들고있는 DrawLine과 함수명은 같지만

graphics클래스의 내부 함수이다. pen,x1,y1,x2,y2순으로 매개변수를 받아 선을 그려준다.

Pen에는 p를 x1자리에 center.X+x1을. y1자리에 center.Y + y1으로 설정해준다.

x2자리에 center.X + x2를  y2자리에 center.Y + y2를 대입하여 함수를 실행하는 함수이다.

private void DrawClockFace()
    {
      Pen p = new Pen(Brushes.LightSteelBlue, 30);
      g.DrawEllipse(p,
        center.X - clockSize / 2,
        center.Y - clockSize / 2,
        clockSize,
        clockSize);
    }

다음은 DrawClockFace로 시계의 테두리를 그려주는 함수이다.

Pen p를 색상은 lightBlue로 굵기는 30으로 설정해준다.

g.DrawEcllipse함수를 사용하여 타원(원)을 생성해줄 것이다.

기준이 조금 특이한데 pen , x , y , width , height 를 매개변수로 갖는다.

x,y지점을 upperLeft로 라는 width,height의 사각형을 생성하여 안쪽에 네 변에 모두 닿는 원을 그리는 방식이다.

여기서는 panel의 중앙을 x,y로 잡고 시계의 크기만큼 빼준 곳을 기준으로 반지름이 2*clockSize인 원의 테두리를 그려주었다.

private void aClockSetting()
    {
      center 
        = new Point(clientSize / 2, clientSize / 2);
      radius = clockSize / 2;

      hourHand = (int)(radius * 0.45);
      minHand = (int)(radius * 0.55);
      secHand = (int)(radius * 0.65);
    }

다음은 아날로그시계를 세팅해보았다.

center를 여기서 설정하게된다.

center의 넓이,높이를 새 좌표 client의 절반으로 설정해준다.

radius(반지름)을 clockSize의 절반으로 해 주었다.

시침을 반지름의 0.45배로 분침을 0.55배 초침을 0.65배로 설정해주고 int형으로 변환해서 저장해주었다.

private void DrawHands(double radHr, double radMin, double radSec)
    {
      // 시침(현재 시간의 좌표를 각도를 이용하여 구하자)
      DrawLine(0, 0,
        (int)(hourHand * Math.Sin(radHr)),
        (int)(hourHand * Math.Cos(radHr)),
        Brushes.RoyalBlue, 8);

      // 분침(현재 시간의 좌표를 각도를 이용하여 구하자)
      DrawLine(0, 0,
        (int)(minHand * Math.Sin(radMin)),
        (int)(minHand * Math.Cos(radMin)),
        Brushes.SkyBlue, 6);

      // 초침(현재 시간의 좌표를 각도를 이용하여 구하자)
      DrawLine(0, 0,
        (int)(secHand * Math.Sin(radSec)), 
        (int)(secHand * Math.Cos(radSec)),
        Brushes.OrangeRed, 4);

      // 배꼽
      int coreSize = 16;
      Rectangle r = new Rectangle(
        center.X - coreSize / 2, center.Y - coreSize / 2,
        coreSize, coreSize);
      g.FillEllipse(Brushes.Gold, r);
      g.DrawEllipse(new Pen(Brushes.Green, 3), r);
    }

마지막으로 바늘을 그리는 함수이다.

DrawLine함수를 사용하여 0,0에서부터(현재 0,0은 cente.x , cexter.y이다)현재시간의 시,분,초에 대한

rad값의 sin을 높이(y좌표)로 cos를 넓이(x좌표)로 사용하고 시침은 로열블루 분침은 스카이블루 초침은 오렌지레드로 설정해주었다.

다음으로는 시계의 배꼽을 만들어주기 위해

coresize를 16으로 설정하고 16x16의 사각형을 p-8,p-8에 생성해준다.

그다음 속이 꽉 찬 원을 gold색상으로 방금 생성해준 사각형에 넣어준다.

그 후 이 금색 원을 테두리로 감싸기 위해 

타원을 하나 그려줄건데 green색상으로 너비는 3을 가지는 원을 그려준다.

잘 나온다.

 


[2]이 아날로그 시계를 WPF로도 만들어보았다.

<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">
  <Grid Margin="10">
    <Canvas x:Name="canvas1" Width="250" Height="250">
      <Ellipse x:Name="aClock" Width="250" Height="250"/>
    </Canvas>
  </Grid>
</Window>

xaml코드이며 title을 WPF Clock으로 높이는 350 넓이도 350으로 설정해주었다.

grid의 margin을 10을 주었고 

canvas1을 canvas타입으로 추가해주었다. 높이와 너비는 250이다.

이 캔버스안에 타원(원)을 생성해줄건데 높이와 너비는 250으로 방금 생성해준 사각형과 크기를 맞출 것이다.

이 원의 name이 aClock이다.

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;
    public MainWindow()
    {
      InitializeComponent();

      aClockSetting();
      timerSetting();
    }

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

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

      canvas1.Children.Clear();
      DrawClockFace();  // 시계판 그리기

      // 시간에 따라 시계바늘을 그린다
    }

    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);
    }
  }
}

다음은 cs코드이다.

Point center;
    int radius;
    int hourHand;
    int minHand;
    int secHand;
    public MainWindow()
    {
      InitializeComponent();

      aClockSetting();
      timerSetting();
    }

window의 전역변수로 반지름,시침,분침,초침을 선언해주었다.

다음 메인 윈도우함수 안에는 aClockSetting()함수와 timerSetting()함수를 선언해주었다. 추후에 작성할 예정이다.

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

timerSetting함수의 코드이다.

WPF에서는 windows form app과는 다르게 timer대신 DispatcherTimer라는 것을 사용한다.

using System.Windows.Threading;

이 using을 선언해 주어야 사용가능하다.

interval은 10밀리초로 

이벤트 메서드Tick 은 T_Tick으로 

마지막으로 setting과 함께 타이머를 start해준다.

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

      canvas1.Children.Clear();
      DrawClockFace();  // 시계판 그리기

      // 시간에 따라 시계바늘을 그린다
    }

다음은 이벤틀핸들러 Timer_Tick을 작성해준다.

Datetime 클래스의 c를 Now로 받아준다.

canvas1의 children을 모두 clear해준 뒤(바늘들의 흔적이 남는 것을 방지)

DrawClockFace함수를 사용하여 시계판을 그려준다.

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

시계판을 생성하는 DrawClockFace이다.

xaml에서 선언해준 aclock타원의 stroke프로퍼티를(색상을) lightsteelblue로 지정해준다.

그 후 aclock의 선의 굵기를 30으로

canvas에 방금 설정해준 타원 aClock을 children으로 Add해준다.

 

 

현재 여기까지 구현함 다음시간에 이어서 할 예정입니다.

 

감사합니다.

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

VP(22-06-15)  (0) 2022.06.18
VP(22-06-10)  (0) 2022.06.18
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
글 보관함