티스토리 뷰
[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 |