11 October 2013

สร้างนาฬิกาอนาล็อกด้วย C#

[ย้ายบทความจาก Gushared.com]
    Analog Clock ก็คือนาฬิกาที่เป็นเข็มๆนั่นแหละครับคงจะรู้จักกันดี แต่เคยสงสัยไหมครับว่าถ้าเราจะสร้างมันได้ยังไงโดยการเขียนโปรแกรม เดี๋ยวผมจะลองเขียนโดย C# ก่อนแล้วกันนะครับเพราะง่ายสำหรับผมตอนนี้ ส่วนใครที่อยากได้โค๊ดของจาวาก็คงต้องรอไปก่อนนะครับ
    ขั้นตอนที่ 1 สร้าง Windows Forms Application ขึ้นมาก่อนในที่นี้ผมตั้งชื่อโปรเจคว่า AnalogClock
    ขั้นตอนที่ 2 นำ Panel จาก ToolBox มาวางบน Form และเปลี่ยน Properties ดังนี้
 Name : ClockPanel, BackColor : Black, Size : [300, 300]
    ขั้นตอนที่ 3 นำ Button จาก ToolBox มาวางบน Form และเปลี่ยน Properties ดังนี้
 Name : SetTime, Text : Set Time
    ขั้นตอนที่ 4 นำ NumericUpDown จาก ToolBox มาวางบน Form จำนวน 3 อัน โดยจะใช้เป็นตัวกำหนดค่าของ วินาที, นาทีและชั่วโมง โดยเปลี่ยน Properties ดังนี้
ส่วนของวินาที Name : UDsec, Maximum : 60, Minimum : 0, Value : 0
ส่วนของนาที Name : UDmin, Maximum : 60, Minimum : 0, Value : 0
ส่วนของชั่วโมง Name : UDhour, Maximum : 12, Minimum : 0, Value : 0
    ส่วนทั้งหมดนี้จะเป็นส่วน GUI ทั้งหมดที่เราจะใช้ผู้อ่านสามารถปรับแต่งได้ตามความต้องการครับ ^_^
    ขั้นตอนที่ 5 ในส่วนนี้เราจะมาเรียนรู้เรื่องการวาดเข็มนาฬิกากันครับ ซึ่งจะมีคณิตศาสตร์เข้ามาเกี่ยวข้องนิดหน่อย ส่วนพารามิเตอร์หลักที่เราจำเป็นต้องใช้คือ จุดศูนย์กลางของ Panel (xCenter, yCenter), ความยาวของเข็มนาฬิกาซึ่งมีทั้งหมด 3 อัน(secLength, minLength, hourLength) และจุดปลายของเข็มทั้ง 3 ที่เราจะวาดนั่นแหละครับ(xSec, ySec, xMin, yMin, xHour, yHour) แต่เอ๊ะ! แล้วเราจะรู้ได้ยังไงหล่ะครับว่าจุดปลายจะเอามาจากไหน เราจะสามารถหาจุดปลายของเข็มนาทีได้ดังนี้ครับ
xSec = xCenter + secLength*sin(θ)
ySec = yCenter - secLength*cos(θ)
 θ = second*(2π/60) -> ส่วนของวินาที
 θ = (minute+second/60)*(2π/60) -> ส่วนของนาที
 θ = (hour%12+minute/60))*(2π/12) -> ส่วนของชั่วโมง
    สามารถเขียนโค๊ดได้ดังต่อไปนี้
xSec = Convert.ToInt32(xCenter+SecLength*Math.Sin(sec*(((2*Math.PI)/60))));
ySec = Convert.ToInt32(xCenter-SecLength*Math.Cos(sec*(((2*Math.PI)/60))));
xMin = Convert.ToInt32(xCenter + MinLength * Math.Sin(min * (((2 * Math.PI) / 60))));
yMin = Convert.ToInt32(xCenter - MinLength * Math.Cos(min * (((2 * Math.PI) / 60))));
xHour = Convert.ToInt32(xCenter + HourLength * Math.Sin((hour % 12 + min / 60) * ((2 * Math.PI) / 12)));
yHour = Convert.ToInt32(yCenter - HourLength * Math.Cos((hour % 12 + min / 60) * ((2 * Math.PI) / 12)));
    ขั้นตอนที่ 6 ให้เราทำการสร้าง Event Paint ของ Panel ขึ้นมาซึ่งจะใช้วาดองค์ประกอบหลักของนั่นก็คือวงกลมขอบนาฬิกาและตัวเลข ตามโค๊ดต่อไปนี้
        private void ClockPanel_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = ClockPanel.CreateGraphics();
            g.DrawEllipse(new Pen(Color.Yellow), xCenter-130, yCenter-130, 260, 260); //วาดวงกลมสีเหลืองขนาด 260*260 
            g.DrawString("3", new Font("Arial", 16), new SolidBrush(Color.Green), xCenter + 110, yCenter-10);
            g.DrawString("6", new Font("Arial", 16), new SolidBrush(Color.Green), xCenter - 10, yCenter + 106);
            g.DrawString("9", new Font("Arial", 16), new SolidBrush(Color.Green), xCenter - 130, yCenter - 10);
            g.DrawString("12", new Font("Arial", 16), new SolidBrush(Color.Green), xCenter - 16, yCenter - 130);
        }
    ขั้นตอนที่ 7 ให้เราทำการสร้าง Event Click ของปุ่ม SetTime แล้วเพิ่มโค๊ดต่อไปนี้ลงไป
  ClockPanel.Refresh();
  int sec = Convert.ToInt32(UDsec.Value);   //อ่านค่าจาก NumericUpDown
  int min = Convert.ToInt32(UDmin.Value);
  int hour = Convert.ToInt32(UDhour.Value);
  
  xSec = Convert.ToInt32(xCenter+SecLength*Math.Sin(sec*(((2*Math.PI)/60))));
  ySec = Convert.ToInt32(xCenter-SecLength*Math.Cos(sec*(((2*Math.PI)/60))));

  xMin = Convert.ToInt32(xCenter + MinLength * Math.Sin(min * (((2 * Math.PI) / 60))));
  yMin = Convert.ToInt32(xCenter - MinLength * Math.Cos(min * (((2 * Math.PI) / 60))));

  xHour = Convert.ToInt32(xCenter + HourLength * Math.Sin((hour % 12 + min / 60) * ((2 * Math.PI) / 12)));
  yHour = Convert.ToInt32(yCenter - HourLength * Math.Cos((hour % 12 + min / 60) * ((2 * Math.PI) / 12)));

  Graphics g = ClockPanel.CreateGraphics();
  g.DrawLine(new Pen(Color.Red), xCenter, yCenter, xSec, ySec);
  g.DrawLine(new Pen(Color.Yellow,3), xCenter, yCenter, xMin, yMin);
  g.DrawLine(new Pen(Color.White,3), xCenter, yCenter, xHour, yHour);
  g.DrawLine(new Pen(Color.Red), xCenter, yCenter, xSec, ySec);
    จากนั้นก็ลองรันโปรแกรมดูนะครับว่าผลลัพธ์เป็นยังไง