ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • GDI+ , 타이머(타이머를 통해서 시계를 구현한다), 마우스와 키보드 (마우스/키보드 입력값을 확인한다)
    .NET 2008. 11. 19. 11:18
    반응형





    /////////////////////////////////////////////////////////

    서버타이머는 Tick이아니라 TimerCallback 로 처리한다  

    /////////////////////////////////////////////////////////



    이 모든 내용은 영진닷컴에서 2007년 1월에 나온 최재규님의 C# Programming Bible with .Net Framework 3.0을 기준으로 한다.

    목차

    • GDI+ 개요
    • Point / Size 구조체
    • GDI+ 그리기 예제
    • 타이머
    • 마우스와 키보드
    • 인쇄하기

    학습목표

    • GDI+를 사용하는 이유를 안다
    • Point/Size구조체를 배워서 GDI+ 기초를 배운다
    • 그리기 예제를 통해 GDI+를 실습한다
    • 타이머를 통해서 시계를 구현한다
    • 마우스/키보드 입력값을 확인한다
    • 인쇄하는 방법을 연구한다

     

    타이머

    타이머는 일정 시간마다 프로그램에 일정한 동작을 시켜주기 위해 필요한 장치이다. 타이머는 서버, 윈도우, 스레드 타이머가 있는데 잘 사용하면 아주 편리하다.

    • System.Timers.Timer
    • System.Windows.Form.Timer
    • System.Threading.Timer

     

    서버 타이머

    서버 타이머는 밀리초 다위로 타이머 시간을 설정할 수 잇는 정확도가 높은 타이머이다. 보통 24시간 이상 동작하면서 연속된 데이터를 처리하는 웹 서버등에 사용되기 때문인지 명칭이 그러한것 같다. 다음 예제는 사용자가 키보드의 q를 누를 때까지 계속 동작하는 프로그램이다.

    1. class ServerTimer
      {
          static void Main(string[] args)
          {

              System.Timers.Timer serverTimer = new System.Timers.Timer();
              serverTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);       // 지정 시간지나고 실행되는 이벤트
              serverTimer.Enabled = true;
              serverTimer.Interval = 1000;    // 호출 시간 1초


              Console.WriteLine("종료하려면 q를 입력하세요: ");
              while (Console.Read() != 'q') ;       // q를 입력하고 엔터를 누르면 잠시후 종료
          }

       


          private static void OnTimedEvent(object sender, ElapsedEventArgs e)

       

          {
              Console.WriteLine("서버 타이머 이벤트 발생 : {0} ", e.SignalTime.ToString());
          }
      }

    servertimer.gif

    윈도우 타이머

    윈도우 타이머는 정말로 사용하기가 쉽다. 윈폼 프로젝트로 열고 왼쪽에 있는 모든 Windows Forms 메뉴에 있는 Timer 컨트롤을 윈폼위에 드래그하면 작업창에 아래와 같이 컨트롤을 확인 할 수 있다.

    timerControl.gif projectProperty.gif

    윈폼으로 열었던 프로젝트에서 솔루션 탐색기 위에서 오른쪽 버튼으로 속성을 선택하여 콘솔 응용 프로그램으로 변경하고 아래에 있는 코드를 작성하면 된다.

    1. public partial class WinTimer : Form
      {
          int timecount = 0, totalTime = 5;
          public WinTimer()
          {
              this.Text = totalTime + "초후 닫히는 창 예제";
              InitializeComponent();
              timer1.Interval = 1000;
          }
          private void WinTimer_Load(object sender, EventArgs e)
          {
              Console.WriteLine("타이머 시작!");

              timer1.Start();
          }
          private void timer1_Tick(object sender, EventArgs e)

          {
              if (timecount < totalTime)
              {
                  Console.WriteLine("{0} Tick...", DateTime.Now);
                  this.Text = (totalTime - timecount) + "초 남았습니다.";
                  timecount++;
              }

              else
              {
                  timer1.Stop();
                  MessageBox.Show("프로그램을 종료합니다.", totalTime + "초 타이머");
                  this.Close();
              }

          }
      }

    timerResult.gif

    스레드 타이머

    마지막으로 스레드 타이머이다. 타이머 중에서 가장 안정적이고 정확하게 시간을 체크할 수 있는 타이머이다. 스레드 형태로 메서드들이 쓰이기 때문에 델리게이트나 콜백함수에 대해서 잘 알고 있어야 하지만, 조금만 관심을 가지면 쉽게 사용하는 방법을 익힐 수 있다.

    1. using System;
      using System.Collections.Generic;
      using System.Text;
      using System.Threading;     // 스레드를 위한 네임스페이스

      namespace ThreadTimer  {
          class TimerExamState {
              public Int64 counter = 0;
              public Timer timer;
          }
          class tTimer {       
              static void Main(string[] args) {
                  TimerExamState tes = new TimerExamState();                  // 타이머 처리를 위한 클래스 생성
                  TimerCallback timerCall = new TimerCallback(CheckStatus);      // 타이머 콜백 대리자(Delegate) 생성
                  Timer timer = new Timer(timerCall, tes, 0, 1000);
      // Timer(부르는 콜백함수명, 같이사용하는 TimerState클래스, 최초시작시간, 시간간격)
                  tes.timer = timer;
                  while (tes.timer != null) ;
              }

              private static void CheckStatus(Object state) {
                  TimerExamState ts = (TimerExamState)state;
                  ts.counter++;
                  if (ts.counter == 3)  {    ⓐ
                      Console.WriteLine("{0}:스레드 체크 : {1}.", ts.counter, DateTime.Now);
                      (ts.timer).Change(5000, 2000);                           // 실행도중 타이머의 설정을 수정할 수 있음
                      Console.WriteLine("스레드 상태 변경...");
                      Console.WriteLine("5초후에 2초 간격으로 다시 시작됩니다.");
                  } else if (ts.counter == 4)  {
                      Console.WriteLine("스레드 상태 변경 => 2초 간격으로 시작");
                      Console.WriteLine("{0}:스레드 체크 : {1}.", ts.counter, DateTime.Now);
                  } else if (ts.counter == 7)  {
                      Console.WriteLine("타이머를 종료합니다...");
                      ts.timer.Dispose();                  // 타이머 종료때 타이머 리소스 해제
                      ts.timer = null;
                  } else  {
                      Console.WriteLine("{0}:스레드 체크 : {1}.", ts.counter, DateTime.Now);
                  } ⓑ //Console.WriteLine("{0}:스레드 체크 : {1}.", ts.counter, DateTime.Now);
              }
          }
      }

    결과는 아래와 같다.

    threadTimerResult.gif 최초에 1부터 3까지는 1초간격으로 실행되다가 counter가 4가 되었을때 전체를 5초 대기 후 2초간격으로 실행시킨다. 그런뒤 counter가 7이되면 스레드 타이머 자체를 중지시킨다. 전체 실행과정이며 ⓐ부터 ⓑ까지 부분을 주석으로 처리하고 ⓑ뒤에 주석처리되어 있는 부분만을 실행시키면 끝나지 않는 시계로 동작하는 콘솔 프로그램이 확인될 것이다.

    타이머 응용 / 윈도우 기반 시계만들기

    어떤 타이머를 사용해도 무방하지만 가장 간단한 윈도우 타이머를 사용하여 아날로그 시계를 만들어보도록 하자.

    윈폼 프로젝트에서 선택하고 폼에 들어있는 속성중에 아래에 리스트와 같이 변경한다.

    • FormBorderStyle : None
    • MaximizeBox : False
    • MinimizeBox : False
    • StartPosition : CenterScreen

    이후, 타이머 컨트롤을 올려놓고 아래와 같이 코딩한다.

    1. ...
      using System.Drawing.Drawing2D;

      namespace AnalogClock  {
          public partial class Clock : Form    {
              int baseX, baseY, clockW, clockH;
              public Clock()  {
                  InitializeComponent();
                  baseX = 0; baseY = 0; clockW = 300; clockH = 300;
                  timer1.Interval = 1 * 1000; timer1.Enabled = true;
              }

              private void timer1_Tick(object sender, EventArgs e)  {
                  Invalidate();
              }

              protected override void OnPaint(PaintEventArgs e)  {
                  Graphics g = e.Graphics;
                  DrawAnalogClock(g);

                  base.OnPaint(e);
              }

              private void DrawAnalogClock(Graphics g)  {
                  int center = baseX + clockH / 2;
                  long seconds = DateTime.Now.Hour * 60 * 60 + DateTime.Now.Minute * 60 + DateTime.Now.Second;

                  double hourAngle = 2 * Math.PI * (seconds - 15 * 60 * 60) / (12 * 60 * 60);
                  double minuteAngle = 2 * Math.PI * (seconds - 15 * 60) / (60 * 60);
                  double secondAngle = 2 * Math.PI * (seconds - 15) / 60;

                  g.DrawEllipse(new Pen(Brushes.Black, 3), baseX, baseY, clockW, clockH);
                  g.DrawLine(new Pen(Brushes.Red, 7), center, center, center + (int)(100 * Math.Cos(hourAngle)), center + (int)(100 * Math.Sin(hourAngle)));
                  g.DrawLine(new Pen(Brushes.Green, 5), center, center, center + (int)(130 * Math.Cos(minuteAngle)), center + (int)(130 * Math.Sin(minuteAngle)));
                  g.DrawLine(new Pen(Brushes.Blue, 5), center, center, center + (int)(145 * Math.Cos(secondAngle)), center + (int)(145 * Math.Sin(secondAngle)));
                  this.Text = "아날로그 시계 : " + DateTime.Now.ToShortTimeString();
              }

              private void Clock_Click(object sender, EventArgs e)  {
                  this.Close();
              }
          }
      }

     

    AnalogClock.gif 좀 작게 줄였지만 모양은 왼쪽의 것과 같이 나온다.

     

    마우스와 키보드

    키보드는 가장 오래된 입력장치 중 하나이며, 마우스는 GUI 환경에서 꼭 필요한 필수 입력장치이다. 이 두 장치에 대한 정보도 처리하여 입력되는 값이나 위치를 프로그램에 반영할 수 있다.

    키보드

    키의 입력에는 4종류가 있다

    • 문자키 : 문자, 숫자, Space, BackSpace, Esc
    • 비문자키 : 방향키, 펑션키, 삽입 등의 문자입력과 연관없는 값
    • 토글키 : Caps Lock, Num Lock, Scroll Lock, Insert 등
    • 쉬프트키 : Shift, Alt, Ctrl 등 조합되는 키

    Control 클래스를 상속받은 하위 클래스에서 키에 대한 대표적인 이벤트는 KeyDownKeyUp이 있다. KeyDown은 키보드가 눌려져서 있는 상태에 발생하고,  KeyUp은 눌려진 키를 다시 놓으면 발생한다.

    키보드 관련 이벤트 핸들러의 매개변수에 KeyEventArgs클래스 인스턴스가 필요하고 여기에는 다음과 같은 속성이 존재한다.

    • Alt: Alt키가 눌려졌는지 여부 [bool]
    • Control: Ctrl키가 눌려졌는지 여부 [bool]
    • Handled: 이벤트 처리 여부 [bool]
    • KeyCode: 키보드 코드 반환 [Keys]
    • KeyData: 누른 키에 대한 키코드와 동시에 누른 Shift 키들에 대한 조합 [Key]
    • KeyValue: KeyCode 속성 정수값 [int]
    • Modifiers: 하나이상의 보조키 플래그 [Keys]
    • Shift: Shift키 눌려졌는지 여부 [bool]
    • SuppressKeyPress: 키 이벤트 내부 컨트롤에 전달할지 여부 [bool]

    다음으로 KeyPress메서드가 있다. 이는 컨트롤에 포커스가 있을때 키를 누르면 발생하는 이벤트이다. 이벤트 발생순서는 KeyDown → KeyPress → KeyUp 순으로 발생한다. KeyPress이벤트 핸들러의 메서드의 매개변수는 KeyPressEventArgs클래스 인스턴스이다.

    • KeyChar : 유니코드 문자 [char]
    • Handled : KeyPress 이벤트가 처리되었는지 여부 [bool]

    예제를 보도록 하자. 이 예제를 실습하면 키보드에 대한 이해를 쉽게 할 수 있다.

    1. string strData = "";
      static void Main(string[] args)  {
          Application.Run(new KeyTest());
      }
      public KeyTest()  {
          this.Text = "문자 입력 예제";
          this.BackColor = Color.Black;
          this.ForeColor = Color.White;
          this.Size = new Size(500, 600);
          this.KeyDown += new KeyEventHandler(KeyTest_KeyDown);
          this.KeyPress += new KeyPressEventHandler(KeyTest_KeyPress);
          this.KeyUp += new KeyEventHandler(KeyTest_KeyUp);

      }
      private void KeyTest_KeyDown(object sender, KeyEventArgs e)  {
          strData += String.Format("\n ① {0} KeyDown", e.KeyCode);
          Invalidate();
      }
      private void KeyTest_KeyUp(object sender, KeyEventArgs e)  {
          strData += String.Format("\n ② {0} KeyUp", e.KeyCode);
          Invalidate();
      }
      private void KeyTest_KeyPress(object sender, KeyPressEventArgs e)  {
          strData += String.Format("\n ③ {0} KeyPress", e.KeyChar);
          Invalidate();
      }
      protected override void OnPaint(PaintEventArgs e)  {
          Graphics g = e.Graphics;
          g.DrawString(strData, new Font("맑은 고딕", 10, FontStyle.Bold), Brushes.White, 20, 30);           
          base.OnPaint(e);
      }

     

    KeyTest.gif

    마우스

    마우스는 GUI(Graphic User Interface)에서 가장 기본이 되는 입력장치이다. 첫번째로 마우스에 대한 등록 정보를 출력하는 간단한 예제를 먼저 보도록 하자.

    1. 11 public partial class Form1 : Form

      12 {

      13     public Form1()

      14    {

      15       InitializeComponent();

      16    }

      17

      18    private void btn_MouseCheck_Click(object sender, EventArgs e)

      19    {

      20         String strMI = String.Format("휠 마우스 설치 : {0} \n 마우스 버튼 개수 : {1} \n " +

      21                  "버튼스왑 : {2} \n 마우스속도 : {3} \n" +

      22                  "휠 델타값 : {4} \n 휠 라인수 : {5} \n" +

      23                  "더블클릭 시간 : {6}ms \n 픽셀단위 영역 : {7}",

      24                  SystemInformation.MouseWheelPresent,

      25                  SystemInformation.MouseButtons,

      26                  SystemInformation.MouseButtonsSwapped,

      27                  SystemInformation.MouseSpeed,

      28                  SystemInformation.MouseWheelScrollDelta,

      29                  SystemInformation.MouseWheelScrollLines,

      30                  SystemInformation.DoubleClickTime,

      31                  SystemInformation.DoubleClickSize);

      32        txt_MouseInfo.Text = strMI;                              

      33     }

      34 }

    별건 아니기 때문에 중요치는 않다.

    무엇보다 중요한건 마우스 이벤트 처리가 어떻게 되는지 확인 하는 것이다. 아래의 코드는 콘솔에서 윈폼을 만들어 폼위에서 마우스 이벤트를 처리하는 코드이다. 꼭 코딩해보자.

    1. 4 using System.Windows.Forms;

      5

      6 namespace MouseEvent

      7 {

      8   class consoleMouseEvent : Form

      9   {

      10    public consoleMouseEvent()

      11    {

      12      this.Text = "마우스확인";

      13      this.MouseClick += new MouseEventHandler(cme_MouseClick);

      14      this.MouseDoubleClick += new MouseEventHandler(cme_MouseDoubleClick);

      15      this.MouseDown += new MouseEventHandler(cme_MouseDown);

      16      this.MouseUp += new MouseEventHandler(cme_MouseUp);

      17      this.MouseWheel += new MouseEventHandler(cme_MouseWheel);

      18      this.MouseMove += new MouseEventHandler(cme_MouseMove);

      19    }

      20

      21    static void Main(string[] args)

      22    {

      23      Application.Run(new consoleMouseEvent());

      24    }

      25

      26    protected void cme_MouseClick(object sender, MouseEventArgs me)

      27    {

      28      Console.WriteLine("{0} 마우스 클릭", me.Clicks);

      29    }

      30

      31    protected void cme_MouseDoubleClick(object sender, MouseEventArgs me)

      32    {

      33      Console.WriteLine("{0} 마우스 더블클릭", me.Button);

      34    }

      35

      36    protected void cme_MouseDown(object sender, MouseEventArgs me)

      37    {

      38      Console.WriteLine("{0} 마우스다운", me.Button);

      39    }

      40

      41    protected void cme_MouseUp(object sender, MouseEventArgs me)

      42    {

      43      Console.WriteLine("{0} 마우스업", me.Button);

      44    }

      45

      46    protected void cme_MouseWheel(object sender, MouseEventArgs me)

      47    {

      48      Console.WriteLine("{0} 마우스휠", me.Delta);

      49    }

      50

      51    protected void cme_MouseMove(object sender, MouseEventArgs me)

      52    {

      53      Console.WriteLine("{0}, {1} 마우스이동", me.X, me.Y);

      54    }      

      55  }

      56 }

     

    반응형

    댓글

Designed by Tistory.