'Drag Rectangle WPF Shape MouseCapture'에 해당되는 글 1건

  1. 2010.09.13 마우스 드래그를 이용한 사각형 그리기 6

안녕하세요? 맨날맑음 입니다.

이번 포스팅은 WPF에서 마우스 드래그를 이용한 간단한 사각형 그리기입니다. 이 예제를 응용하면 원이나 선도 그릴 수 있고, 자료구조를 이용하면 윈도우 그림판과 같은 기능도 쉽게 만들 수 있습니다.

-Fig1. 사각형을 그리는 WPF 어플리케이션-

Fig1에서 보는 바와 같이 마우스의 현재 좌표를 왼쪽 상단에 표시해 주며, 드래그를 이용하여 사각형을 그리는 기능을 합니다. WPF에서 제공하는 InkCanvas객체를 이용하면 더 간단하게 구현도 가능 하겠네요^^; 하지만 이번에는 Grid에 사각형을 그리는 방법으로 구현해 보겠습니다.

 

 

#1. 마우스 이벤트

-Fig2. WPF Window의 마우스 이벤트-

WPF의 컨트롤은 마우스 이벤트를 가지고 있습니다. 마우스 다운이나 업, 마우스 무브, 마우스 휠 등 이벤트를 지원하는데요. 우리 예제에서는 MouseLeftButtonDown과 MouseMove, MouseLeftButtonUp 세 가지 이벤트를 사용합니다. 마우스 이벤트 핸들러에서는 MouseEventArgs 객체가 인자로 넘어오고 이 이벤트객체를 이용하면 현재 마우스의 상태정보를 알 수 있습니다.

 

이름

설명

Device

이 이벤트를 시작한 입력 장치를 가져옵니다. (InputEventArgs에서 상속됨)

Handled

라우트된 이벤트가 경로를 따라 이동할 때의 현재 이벤트 처리 상태를 나타내는 값을 가져오거나 설정합니다.

LeftButton

마우스 왼쪽 단추의 현재 상태를 가져옵니다.

MiddleButton

마우스 가운데 단추의 현재 상태를 가져옵니다.

MouseDevice

이 이벤트와 연결된 마우스 장치를 가져옵니다.

OriginalSource

부모 클래스에서 Source를 조정하기 전에 순수 적중 테스트에 의해 결정되는 원본 보고 소스를 가져옵니다.

RightButton

마우스 오른쪽 단추의 현재 상태를 가져옵니다.

RoutedEvent

RoutedEventArgs 인스턴스와 연결된 RoutedEvent를 가져오거나 설정합니다. (RoutedEventArgs에서 상속됨)

Source

이벤트를 발생시킨 개체에 대한 참조를 가져오거나 설정합니다. (RoutedEventArgs에서 상속됨)

StylusDevice

이 이벤트와 연결된 스타일러스 장치를 가져옵니다.

Timestamp

이 이벤트가 발생한 시간을 가져옵니다. (InputEventArgs에서 상속됨)

XButton1

첫 번째로 확장된 마우스 단추의 현재 상태를 가져옵니다.

XButton2

두 번째로 확장된 마우스 단추의 현재 상태를 가져옵니다.

- MouseEventArgs 의 속성 (출처 : MSDN)-

이벤트 객체의 속성을 통해 마우스의 현재 상태정보를 알 수 있으며, GetPosition() 메서드를 이용하면 마우스 포인트의 좌표를 얻어 올 수도 있습니다.

 

#2. Shape객체

WPF에서 Rectangle, Ellipse, Polygon과 같은 모든 도형의 기본 클래스는 Shape입니다. Shape는 UI 요소이므로 패널이나 대부분의 컨트롤에서 사용 할 수 있습니다. Stroke 속성을 사용하면 도형의 테두리(윤곽선)의 색상을 지정 할 수 있고, StrokeThickness 속성을 이용하면 도형의 테두리 두께를 설정 할 수 있습니다. 또한 Fill 속성을 이용하면 도형의 표면 색상을 설정 할 수 있습니다.

 

-Fig3. 여러 속성을 적용하여 랜더링 된 원의 모습-

 

#3. 코드 구현

코드가 간단하여, 대부분의 설명은 주석으로 코드설명을 대신합니다. WPF 프로젝트를 생성하고, 다음과 같은 코드를 넣어 줍니다.

 

    

-Code1. MainWindow.xaml-

 

 
public partial class MainWindow : Window
 {
     /// 
     /// 드레그를 시작한 마우스 좌표;
     /// 
     Point prePosition;
     /// 
     /// 현재 그려지는 사각형
     /// 
     Rectangle currentRect;

     public MainWindow()
     {
         InitializeComponent();
         //이벤트 핸들러 생성
         this.root.MouseLeftButtonDown += new MouseButtonEventHandler(root_MouseLeftButtonDown);
         this.root.MouseMove += new MouseEventHandler(root_MouseMove);
         this.root.MouseLeftButtonUp += new MouseButtonEventHandler(root_MouseLeftButtonUp);
         
         // 좌표를 나타내는 TextBlock을 최상위로 ...
         Grid.SetZIndex(this.tbPosition, 99999);
     }

     /// 
     /// 마우스 클릭 해제 이벤트 핸들러
     /// 
     /// 
     /// 
     void root_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
     {
         //마우스 캡춰를 제거한다.
         this.root.ReleaseMouseCapture();
         SetRectangleProperty();
         currentRect = null;
     }

     private void SetRectangleProperty()
     {
         //사각형의 투명도를 100% 로 설정
         currentRect.Opacity = 1;
         //사각형의 색상을 지정
         currentRect.Fill = new SolidColorBrush(Colors.LightYellow);
         //사각형의 테두리를 선으로 지정
         currentRect.StrokeDashArray = new DoubleCollection(); ;
     }

     /// 
     /// 마우스 이동 이벤트 핸들러
     /// 
     /// 
     /// 
     void root_MouseMove(object sender, MouseEventArgs e)
     {
         
         //현재 이동한 마우스의 좌표를 얻어온다
         Point currnetPosition = e.GetPosition(this.root);
         //좌표를 표시한다.
         this.tbPosition.Text = string.Format("마우스 좌표 : [{0},{1}]", currnetPosition.X, currnetPosition.Y);
         //마우스 왼쪽 버튼이 눌려있으면
         if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
         {
             if (currentRect != null)
             {
                 //사각형이 나타날 기준점을 설정한다.
                 double left = prePosition.X;
                 double top = prePosition.Y;
                 //마우스의 위치에 따라 적절히 기준점을 변경한다.
                 if (prePosition.X > currnetPosition.X)
                 {
                     left = currnetPosition.X;
                 }
                 if (prePosition.Y > currnetPosition.Y)
                 {
                     top = currnetPosition.Y;
                 }
                 //사각형의 위치 기준점(Margin)을 설정한다
                 currentRect.Margin = new Thickness(left, top, 0, 0);
                 //사각형의 크기를 설정한다. 음수가 나올 수 없으므로 절대값을 취해준다.
                 currentRect.Width = Math.Abs(prePosition.X - currnetPosition.X);
                 currentRect.Height = Math.Abs(prePosition.Y - currnetPosition.Y);
             }
         }
     }

     /// 
     /// 마우스 왼쪽 버튼 클릭 이벤트 핸들러
     /// 
     /// 
     /// 
     void root_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
     {
         //마우스의 좌표를 저장한다.
         prePosition = e.GetPosition(this.root);
         //마우스가 Grid밖으로 나가도 위치를 알 수 있도록 마우스 이벤트를 캡처한다.
         this.root.CaptureMouse();
         if (currentRect == null)
         {
             //사각형을 생성한다.
             CreteRectangle();               
         }
     }

     private void CreteRectangle()
     {
         
         currentRect = new Rectangle();
         currentRect.Stroke = new SolidColorBrush(Colors.DarkGreen);
         currentRect.StrokeThickness = 2;
         currentRect.Opacity = 0.7;
         //사각형을 그리는 동안은 테두리를 Dash 스타일로 설정한다.
         DoubleCollection dashSize = new DoubleCollection();
         dashSize.Add(1);
         dashSize.Add(1);
         currentRect.StrokeDashArray = dashSize;
         currentRect.StrokeDashOffset = 0;
         //사각형의 정렬 기준을 설정한다.
         currentRect.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
         currentRect.VerticalAlignment = System.Windows.VerticalAlignment.Top;
         //그리드에 추가한다.
         this.root.Children.Add(currentRect);
     }
 }

-Code2. MainWindow.xaml.cs-

마우스를 드래그하는 동안은 그림판이나 포토샵에서와 같이 점선으로 사각형의 모양을 표시 해 줄 필요가 있기 때문에 테두리의 속성을 변경 할 필요가 있습니다. 테두리를 점선으로 표시하는 속성은 Rectangle객체의 StrokeDashArray를 사용하여 설정 할 수 있으며, XAML에서는 다음과 같이 표현 할 수 있습니다.

 

-Fig4. StrokeDashArray 속성이 적용 된 Ellipse-

소스 빌드 환경 : VisualStudio2010, .NET Framework4.0

Posted by 맨날맑음
,