http://goo.gl/FHk67U
마우스 더블클릭
void image_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left && e.ClickCount == 2)
{
Close();
}
}
http://dotnetmvp.tistory.com/38
16. [WPF 기초 강좌] 사용자입력 2
안녕하세요.
WPF 기초강좌를 진행하는 김창민입니다.
오늘 강좌를 시작하겠습니다.
키보드 입력은 어떤 요소(컨트롤)가 포커스(Focus)되어있는냐에 따라서 이벤트를 실행하는 요소가 정해지는데 마우스 입력은 어떤 요소가 마우스 화살표 또는 포인터 바로 아래에 위치하고 있느냐에 따라 마우스 이벤트를 실행하게될 요소가 달라집니다. 즉, 마우스 포인터 바로 아래있는 요소가 이벤트를 받게 될 대상이 되는 것입니다.
마우스 입력 역시 UIElement 클래스로부터 파생되어지며 이벤트와 속성등이 제공되어집니다.
- Mouse 클래스
다음 표는 마우스 입력 이벤트들을 나열해 놓은 것입니다.
이벤트 | 설명 |
GotMouseCapture | 컨트롤에 마우스 캡처 중임 |
LostMouseCapture | 컨트롤에서 마우스 캡처를 잃음 |
MouseEnter | 마우스 포인터가 컨트롤의 영역으로 들어왔음 |
MouseLeave | 마우스 포인터가 컨트롤의 영역 밖으로 나감 |
PreviewMouseLeftButtonDown, MouseLeftButtonDown | 마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 왼쪽 버튼이 눌렸을 때 |
PreviewMouseLeftButtonUp, MouseLeftButtonUp | 마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 왼쪽 버튼이 눌렸다 떼어졌을 때 |
PreviewMouseRightButtonDown, MouseRightButtonDown | 마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 오른쪽 버튼이 눌렸을 때 |
PreviewMouseRightButtonUp, MouseRighttButtonUp | 마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 오른쪽 버튼이 눌렸다 떼어졌을 때 |
PreviewMouseDown, MouseDown | 마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 버튼이 눌렸을 때 |
PreviewMouseUp, MouseUp | 마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 버튼이 눌렸다 떼어졌을 때 |
PreviewMouseMove, MouseMove | 마우스 포인터가 컨트롤 영역내어서 움직였을 때 |
PreviewmouseWheel, MouseWheel | 마우스 포인터가 컨트롤 영역내에 있으면서 마우스 휠이 움직였을 때 |
QueryCursor | 마우스 포인터가 컨트롤 영역내에 있는 동안 마우스 포인터의 모양이 결정되었을 때 |
위 이벤트들은 아마 특별히 설명을 하지 않아도 많이 사용하고 많이 보아왔기 때문에 어떤 이벤트들인지 휜히 다 아시리라 생각합니다.
위 표에있는 이벤트들 말고도 Mouse클래스에는 몇가지 속성들과 메서드를을 제공해 줍니다.
다음 예제를 통해서 몇가지 이벤트, 메서드, 속성에 대해 설명을 진행하겠습니다.
우선 VisualStudio 2008을 실행시켜 “MouseInput”이라는 새 프로젝트를 생성합니다.
그리고 프로젝트에 생성된 “Window1”을 “MouseEvent”로 변경하겠습니다.
이번 예제에서는 Mouse의 이벤트 중 MouseDown, MouseMove, MouseUp, MouseRightButtonDown 이벤트를 등록해 사용하고 Mouse의 Capture, GetPosition 메서드에 대해 알아보도록 하겠습니다.
다음으로 MouseEvent.xaml에 Ellipse 컨트롤과 Button 컨트롤, Label 컨트롤을 Window의 Grid 안에 배치하겠습니다.
<!-- MouseEvent.xaml -->
<Window x:Class="MouseInput.MouseEvent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Ellipse Margin="70,47,72,79" Name="ellipse1" Stroke="Black" Fill="Red" />
<Label Height="28" Margin="0,0,0,12" Name="label1" VerticalAlignment="Bottom" HorizontalContentAlignment="Center" >Label</Label>
<Button Name="button1" Height="23" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75">Button</Button>
</Grid>
</Window>
다음은 “MouseEvent.xaml.cs”로 이동하여 이벤트를 등록하고 핸들러부분에 실행될 코드를 작성하겠습니다.
<!-- MouseEvent.xaml.cs -->
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
namespace MouseInput
{
public partial class MouseEvent : Window
{
public MouseEvent()
{
InitializeComponent();
ellipse1.MouseDown += new MouseButtonEventHandler(ellipse1_MouseDown);
ellipse1.MouseMove += new MouseEventHandler(ellipse1_MouseMove);
ellipse1.MouseUp += new MouseButtonEventHandler(ellipse1_MouseUp);
this.MouseRightButtonDown += new MouseButtonEventHandler(Window1_MouseRightButtonDown);
}
void ellipse1_MouseDown(object sender, MouseButtonEventArgs e)
{
label1.Content = "MouseDown";
Mouse.Capture(ellipse1);
}
void ellipse1_MouseMove(object sender, MouseEventArgs e)
{
label1.Content = "MouseMove" + Mouse.GetPosition(ellipse1);
}
void ellipse1_MouseUp(object sender, MouseButtonEventArgs e)
{
label1.Content = "MouseUp" + Mouse.GetPosition(ellipse1);
}
void Window1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (ellipse1.Fill == Brushes.Red)
ellipse1.Fill = Brushes.Blue;
else
ellipse1.Fill = Brushes.Red;
}
}
}
위 코드에서 Window생성자 부분에 이벤트를 등록하는 코드가 있지요?..
…
ellipse1.MouseDown += new MouseButtonEventHandler(ellipse1_MouseDown);
…
전에 강좌를 통해 이벤트를 코드에서 자동등록하는 방법을 설명드렸는데 혹시 모르시거나 잊어버리신 분들이 있으까봐 다시 간단히 설명해 드리겠습니다.
코드에서 이벤트를 등록하려할 때 이벤트를 발생시킬 요소의 아이디를 치시고 ‘.’을 치면 IntelleSence기능이 작동하여 코드를 쉽게 입력할 수 있을 것입니다.
IntelleSence 창에서 원하는 코드를 찾는데 저는 ellipse1에 MouseDown이벤트를 만들어주기 위해 MouseDown 이벤트를 찾아 선택을 해주겠습니다.
다음으로 “ellipse1.MouseDown” 이 코드 뒤에 이벤트 핸들러를 연결해 주기위해 “+=” 를 입력하면 다음과 같은 설명이 나오게 될 것입니다.
우리는 생각 할 것 없이 시키는데로 “Tab”키를 눌러주면 됩니다.
그러면 코드가 자동으로 생성이되며 이벤트 핸들러 메서드를 작성할 것이라는 안내문이 나옵니다.
그럼 또 우린 생각할 것 없이 “Tab”키를 한번 더 눌러줍니다.
ㅋㅋ 너무나도 친절하게 다음과 같은 이벤트 핸들러 역시 자동으로 생성되어지는 것을 보실 수 있을 것입니다.
이 처럼 VisualStudio에서는 자동으로 이벤트를 쉽게 등록할 수 있는 기능을 제공해 줌으로 써 개발자가 좀 더 쉽고 간단하게 이벤트를 만들어 사용할 수 있도록 도와 주고 있습니다.
그럼 다시 본론으로 들어가서 위에 작성한 코드를 잠깐 같이 보고 실행 결과를 보도록 하겠습니다.
코드를 보시면 “ellipse1.MouseDown” 이벤트 핸들러를 보시면 “Mouse.Capture(ellipse1);” 이라는 코드가 있습니다. 마우스의 캡처는 요소(컨트롤)가 모든 마우스의 입력 명령을 받는 시점을 나타내는데 이말은 요소를 캡처하면 마우스 포인터가 요소의 영역안에 있던지 관계없이 마우스의 입력을 받게됩니다. 그러면서 다른 요소, 즉 최상위 요소인 Window까지 Lock이 걸린 것 같은 현상을 보실 수 있습니다.
다음으로 MouseMove, MouseUp 이벤트 핸들러의 코드를 보시면 “Mouse.GetPosition(ellipse1)”라는 메서드를 이용하여 마우스 포인터가 있는 위치 좌표를 Label에 표시해 주게 되어있습니다. 그런데 메서드의 인자로 “ellipse1”이란 요소를 넘겨주게 되어있는데 이는 “GetPosition”메서드에서 마우스 포인터를 좌표상으로 나타내는데 그 기준을 위에 인자로 넘긴 요소를 기준으로 좌표를 나타내게 된다는 것을 의미하게 됩니다.
그리고 Window의 “MouseRightButtonDown” 이벤트 핸들러에서는 “ellipse”에서 설정한 캡처를 해제함을 나타낸는 코드로 되어있습니다.
Button컨트롤의 역할은 마우스 캡처가 되었을 때 버튼 이벤트가 실행되는 지를 보기 위함으로 버튼이 눌려지게 된다면 ellipse의 배경색을 바꾸어주는 역할을 하게 됩니다.
그럼 빌드하여 실행을 시켜 보겠습니다.
(혹시 제 강좌를 보시던 분들 중에 App.xaml파일의 “StartupUri”를 변경하지 않고 실행이 안되신다고 하시는 분들은 이제 없으시겠죠?~ ㅋㅋ)
위와 같은 실행 창이 나오면 우선 버튼(ID:button1)이 정상적으로 동작을 하는지 버튼을 클릭해 보겠습니다.
원의 배경색이 파란색, 빨간색으로 변하는 것으로 보아 버튼 클릭 이벤트는 정삭적으로 동작하는 것을 알 수 있습니다.
그럼 이제 Mouse.Capture를 하기위해 빨간색 원(ID:ellipse1)을 마우스로 포인터를 가져가 보겠습니다.
마우스 포인터는 원안으로 가져가자 밑에 있는 Label에 “MouseMove”라는 글과 함께 좌표가 표시됨을 알 수 있습니다. 그런데 원 밖으로 마우스 포인터를 가져가면 원 밖에서는 마우스가 움직이는 동안 MouseMove이벤트는 동작하지 않는 것알 수 있습니다. 현재는 “MouseMove” 이벤트는 요소 영역안에 있을 때만 동작하게 됩니다.
다시 마우스 포인터는 원안으로 가져가서 원을 클릭해 보겠습니다.
원안에서 마우스를 클릭하자 Label에 “MouseUp”이란 글자와 좌표가 표시됩니다.
MouseUp은 원 안에서 마우스가 “Down”되었다가 바로 “Up”이 되자 “MouseUp”이벤트가 실행된 결과입니다.
우리는 “MouseDown” 이벤트에서 “ellipes1” 요소를 캡처하는 동작을 지정하였습니다.
당연히 마우스가 클릭되는 동작에서 MouseDown 이벤트도 실행이 되었겠지요?~
마우스캡처의 동작을 보기위해 버튼에 마우스 포인터를 이동해 보겠습니다.
그런데 한가지…
위에 결과에서 뭔가 이상한 것이 있지 않은 가요?...
그건 바로 전에 원 밖에서 마우스 포인터이 이동했을 경우에는 MouseMove이벤트가 실행이 되지 않았는데 지금은 원 밖에서 마우스 포인터를 이동시켜도 MouseMove이벤트가 실행이 되어 Label의 좌표가 계속 변경됨을 알 수 있습니다.
처음에 마우스 캡처를 설명한 부분을 잘 기억하고 있으시다면 눈치 채셨을 것입니다.
“마우스의 캡처는 요소(컨트롤)가 모든 마우스의 입력 명령을 받는 시점을 나타내는데 이말은 요소를 캡처하면 마우스 포인터가 요소의 영역안에 있던지 관계없이 마우스의 입력을 받게됨니다.” 라고 위부분에 설명을 해 놓았습니다. 이것으로만 봐도 현재 마우스 요소가 캡처되있는 상태임을 알 수 있습니다.
그럼 계속해서 버튼을 클릭해 보겠습니다.
버튼이 클릭이 되십니까?...
버튼을 클릭하면서 밑에 Label을 보세요. Label에 “MouseDown”, “MouseUp”이란 글자가 변경되는 것으로보아 마우스는 클릭이 되어지는 것을 알 수 있습니다.
하지만 버튼은 클릭 되어지지 않게 됩니다.
이것은 지금 “ellipse1” 요소가 캡처되어 있는 상태이기 때문에 모든 마우스 이벤트는 “ellipse1”이 다 받게 되어있기 때문입니다.
간단한 예제를 통해서 “Mouse.Capture”를 알아보았는데 쉽게 이해가 되셨는지 모르겠습니다.
아직 실행하지 않은 이벤트가 하나 있는데 “MouseRightButtonDown”이벤트 입니다.
결과 창에서 마우스 오른쪽을 클릭해서 마우스 캡처를 해제한 다음에 원 밖에서의 “MouseMove”, 버튼의 클릭이 정상적으로 되는지 확인해 보세요…
이번 예제는 IsMouseOver 속성과 IsMouseDirectlyOver속성에 대해 알아보고 마우스 휠 이벤트에 대한 예제를 만들어보겠습니다.
예제를 만들기전에 간단히 설명을 진행하고 예제의 결과를 보고 이해하는 순서로 진행을 이어가겠습니다.
IsMouseOver 속성과 IsMouseDirectlyOver은 공통점이 있습니다. 그것은 마우스 포인터가 현재 요소 영역안에 위치하고 있는지의 여부를 Boolean 값으로 반환해줍니다.
다시말해 요소영역안에 마우스 포인터가 위치한다면 true, 그렇지 않으면 false를 반환해 준다는 것입니다.
그러나 이둘은 약간의 차이점이 있습니다. IsMouseOver 속성은 요소의 영역안에 마우스 포인터가 위치하면 true를 반환합니다. 요소안에 자식 요소가 있어서 마우스 포인터가 자식요소 영역안에 있다 하더라도 true를 반환한다는 것입니다.
하지만 IsMouseDirectlyOver속성은 다릅니다. 이 속성은 요소의 자식요소 영역안에 마우스 포인터가 위치한다면 false를 반환하게 됩니다. 다시말해 현재 마우스 포인터가 자식요소가 아닌 자기자신 요소 위에 있어야만 true를 반환하게 됩니다.
그리고 휠 이벤트는 마우스 휠이 움직일 때 발생하는 이벤트인데 MouseWheel 이벤트 핸들러의 MouseWheelEventArgs에서 “Delta” 값을 보고 휠이 위로 움직였는지 아래로 움직였는지를 알 수 있습니다.
그럼 다음 예제를 작성하고 실행해 결과를 보세요..
기존 프로젝트에 “MouseEvent1”이라는 이름으로 새 창을 추가하겠습니다.
그런 다음 “MouseEvent1.xaml”페이지에 디자인을 하겠습니다.
<!—MouseEvent1.xaml -->
<Window x:Class="MouseInput.MouseEvent1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MouseEvent1" Height="300" Width="300" MouseWheel="Window_MouseWheel">
<Grid>
<Button x:Name="button1" Margin="24,37,0,129" HorizontalAlignment="Left" Width="107" MouseEnter="button1_MouseEnter" MouseLeave="button1_MouseLeave" >
<Ellipse x:Name="ellipse1" Height="40" Width="40" Fill="Red" MouseEnter="Ellipse_MouseEnter" MouseLeave="ellipse1_MouseLeave" />
</Button>
<Button x:Name="button2" Margin="0,37,25,129" HorizontalAlignment="Right" Width="107" MouseEnter="button2_MouseEnter" MouseLeave="button2_MouseLeave" >
<Rectangle x:Name="Rectangle1" Height="40" Width="40" Fill="Blue" MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle1_MouseLeave" />
</Button>
<Label Margin="0,0,0,69" Name="label1" FontSize="16" HorizontalContentAlignment="Center" Height="42" VerticalAlignment="Bottom">Label</Label>
<Label FontSize="18" Height="42" HorizontalContentAlignment="Center" Name="label2" VerticalAlignment="Bottom">0</Label>
</Grid>
</Window>
그리고 “MouseEvent1.xaml.cs” 페이지에 다음 코드를 작성합니다.
<!-- MouseEvent.xaml.cs -->
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Shapes;
namespace MouseInput
{
public partial class MouseEvent1 : Window
{
public MouseEvent1()
{
InitializeComponent();
}
private void button1_MouseEnter(object sender, MouseEventArgs e)
{
label1.Content = "button1 MouseOver : " + button1.IsMouseOver.ToString();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
label1.Content = "Ellipse MouseOver : " + ellipse1.IsMouseOver.ToString();
}
private void button2_MouseEnter(object sender, MouseEventArgs e)
{
label1.Content = "button2 MouseDirectlyOver : " + button2.IsMouseDirectlyOver.ToString();
}
private void Rectangle_MouseEnter(object sender, MouseEventArgs e)
{
label1.Content = "Rectangle1 MouseDirectlyOver : " + Rectangle1.IsMouseDirectlyOver.ToString();
}
private void button1_MouseLeave(object sender, MouseEventArgs e)
{
label1.Content = "";
}
private void button2_MouseLeave(object sender, MouseEventArgs e)
{
label1.Content = "";
}
private void ellipse1_MouseLeave(object sender, MouseEventArgs e)
{
label1.Content = "button1 MouseOver : " + button1.IsMouseOver.ToString();
}
private void Rectangle1_MouseLeave(object sender, MouseEventArgs e)
{
label1.Content = "button2 MouseDirectlyOver : " + button2.IsMouseDirectlyOver.ToString();
}
private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta == 120)
{
label2.Content = Convert.ToInt32(label2.Content) + 1;
}
else if (e.Delta == -120)
{
label2.Content = Convert.ToInt32(label2.Content) - 1;
}
}
}
}
간단히 코드 설명을 드리자면 디자인에는 두개의 Button과 두개의 Label이 배치되어 있습니다.
그리고 두개의 버튼에는 각각 Rectangle과 Ellipse가 자식요소로 포함이 되어있습니다.
버튼들과 그 자식요소에는 “MouseEnter” 이벤트 들이 선언되어있어 마우스 포인터가 요소위에 올라가면 이벤트를 실행 시킬 것이고 그 이벤트안에는 IsMouseOver 속성과 IsMouseDirectlyOver속성의 반환 값을 label1에 보여주게 되있습니다.
그리고 마우스 휠 움직일 때는 lable2에 1씩 증가, 1씩 감소하는 코드를 작성해 두었습니다.
그럼 App.xaml 파일을 수정하시여 결과를 보도록 하겠습니다..
IsMouseOver 속성
IsMouseDirectlyOver속성
MouseWhee 이벤트
이제 이해가 되시죠?...
휴~ 정말 긴 강좌였습니다.
그리 어렵지않은 내용이였지만 나름 할 말이 많았었내요...
Mouse 클래스 역시 여럽지 않은 개념임으로 MSDN에서 꼭 한번 읽고 넘어 가시길 바랍니다.
http://msdn.microsoft.com/ko-kr/library/system.windows.input.mouse_members.aspx
이번 시간까지 사용자 입력의 키보드 입력과 마우스 입력에 대해 알아보았습니다.
그리고 사용자 입력중에 하나인 스타일러스 펜 입력이 있는데 이 내용은 Tablet PC나 Digitizing PC 에서 테스트 가능한 기능임으로 현재 강좌에서는 진행을 하지 않으려 합니다.
다음 시간에는 처음 강좌를 시작할 때 WPF시작하기라는 주제로 잠깐 훌터보고 넘어갔단 컨트롤들에 대해 좀 더 구체적으로 알아보는 시간을 갖도록 하겠습니다.
긴 강좌 함께 하시느라 수고하셨습니다.
'프로그래밍(Programming) > WPF' 카테고리의 다른 글
WPF treeview custom 편집 추가 하여 사용하기 (0) | 2014.08.26 |
---|---|
키보드 입력 15. [WPF 기초 강좌] 사용자입력 1 (0) | 2014.07.30 |
3. CompositionTarget의 Redering 이벤트 핸들러 이용 (0) | 2014.07.28 |
좋은 강좌 감사합니다.
그런데 이번 isMouseDirectlyOver 예제는 조금 동작이 다른 것 같아요.
button1 위에 올라섰을때 동작은 맞고 , button1의 자식요소인 ellips1에 마우스가 올라가면,
라벨에는 "Ellipse MouseOver : true"가 표시됩니다.
또한 button2 위에 올라섰을 때는 "button2 MouseDirectlyOver : false"가 표시되고 그 자식요소 rectangle1에 마우스가 올라가면, "Rectangle1 MouseDirectlyOver : true"가 표시됩니다.
cs소스의 이벤트처리 안의 내용을 조금 바꿔서 자식요소의 이벤트에서도 button의 isMouseDirectlyOver 를 참조 해 보아도 false이고요.
기본적으로 button2에 마우스가 올라가서 자식요소 안까지 가지 않아도 false가 나오는 것이 이상합니다.
자식요소 위에서 마우스를 다운한 상태를 유지 해 주면 true가 나오네요.