관리 메뉴

새로운 시작, GuyV's lIfe sTyle.

마우스 캡쳐 본문

ⓟrogramming/Silverlight

마우스 캡쳐

가이브 2009. 7. 22. 14:51

보통, 마우스버튼 다운이 일어날 때 곧 '업'이벤트도 일어난다. 하지만 꼭 그런건 아니다.

어떤 녀석을 클릭 중에 마우스를 밖으로 빼버리는 경우가 될 것이고, 마우스업 이벤트는 적용이 안될 것이다.

이런 경우에서도 마우스버튼이 '업'되었다는 것을 알아내기 위해 마우스를 캡쳐하는 기능을 사용할 수 있는데, MouseCapture() 메소드이다. (UIElement 클래스에 정의.. 해서 모~든 실버라이트의 요소에 사용가능)
이녀석을 이용해서 마우스 캡쳐가 끝날 때 까지 MouseLeftButtonDown, MouseLeftButtonUp 이벤트를 알 수 있을 것이다. 물론 이 상태에서는 다른 요소들은 마우스 이벤트를 받을 수 없을 것이다.  그래서 종종 드래그나 사이즈 조절을 하기 위해 사용되는 경우가 많다.

단순하게 이론적으로만은..

MouseDown 되었을 때, 해당 요소에 MouseCapture() 를 주고 (딴 녀석들은 마우스 이벤트를 못 받게..) 그럼 마우스를 누르고 있는 동안은 해당 요소를 점유하니까.. MouseMove로 알아서 할 것들 한 후에, MouseUp일 때에 ReleaseMouseCapture()로 풀어주면.. 끝.


*개인실습 : 정렬된 상자들 놓고 그 상자를 드래그 하면 서로 위치가 바뀌는 기능 구현.
----------------------

[실습후기]

쉬울거라 생각했는데, 허접한 상상력으로 구현은 성공했지만 버그가 살짝 있는 것 같다.
몇시간 끙끙 앓았다.

다음처럼 Border 3개를 배치하고, 각각의 .Name 도 box1, box2, box3 으로 줬다. Tag 값은 1,2,3 으로 줬다.

이벤트 순서는 MouseEnter -> MouseDown -> MouseMove -> MouseUp -> MouseLeave 로 일어날 것 같은데, 난 Down, Move, Up 3개만 썼다.
 


박스에 마우스가 Down 되면 CaptureMouse()가 된다.
마우스의 위치가 박스의 어디에서 이동 되든 그 자리에서 이동하기 위해 (1)현재 마우스를 클릭시에 저장해 놓는다. 또한, (2)해당 박스의 현재 위치도 저장한다. 

다음은 Drag를 위해 Move 이벤트 처리다.
현재 박스가 지금 있는 그 자리에서 마우스의 이동에 따라오기 하기 위해, 아까 Down시 저장한 마우스 좌표값이 사용된다. 단순하게 생각했다. 
 
[ 이동해야되는 값 = MouseMove값 - Down시 저장값 ]

그리고 드래그 중이라면 (Down 중이라면) 현재의 클릭한 박스를 Canvas 좌표에서 '이동해야되는 값'만큼 더한 값을 준다. 당연히 2개, Canvas.Left, Canvas.Top 이다.

이렇게 이동되고 있을 때, 박스가 겹쳤는지 (부딪혔는지) 체크하는 메소드를 호출하게 된다.

가로, 세로 처리를 해야되지만 똑같다. 가로 체크만 보면 이동중인 박스의 X좌표 값과 박스의 길이를 합한 값이 다른 박스보다 크고(오른쪽 부딪힘 체크) 하지만 이동중인 X좌표 값이 체크하는 박스의 X좌표값과 길이를 합한 값보다 작아야 하겠다. (왼쪽까지 체크)
세로도 마찬가지이다.

로직은 대충 박스들의 텍스트 처럼 .Name을 맞추었기 때문에 루프돌렸다. 박스의 갯수에 상관없이 처리되게 하기 위해서이다. 여튼, 그렇게 체크를 하고, 부딪혔다면 박스의 위치를 바꾼다. 부딪힌 박스는 현재 이동중인 박스의 최초 클릭위치 X,Y 좌표로 이동시킨다. 그리고 지금 이동중인 있는 박스의 초기 X,Y값은 부딪힌 박스의 값으로 세트한다. (값 설정 순서는 바뀌어야 한다. 부딪힌 박스는 좌표값이 바뀌면 드래그중인 박스에 좌표값을 줄 수 없기 때문에.. 당연히;;) 

이 부분에서 참 많이 헤맸다. 소스는 부끄러워서 결코 공개하지 않을 것이다 ㅡ.ㅡ;

머리에서 돌아가는 이론과 현실은 참으로 달랐다.
가장 큰 문제점은 "박스가 겹친 후 아래 그림처럼 Box2가 Box1 위치로 이동한 후 Move이벤트에 또 걸린다는 건데.. 집중력 저하로 그저 그렇게 막코딩으로 해결은 봤다.

방법은, 간단하게 드래그시에 부딪히고 있는 중이라면 부딪힌 박스를 기억해놨다가 그녀석이면 그냥 쌩까는 것이다. 그리고 그림에서처럼 드래그중인 Box1이 완전히 Box2에서 벗어난다면 방금 겹쳐졌던 값을 저장하는 곳을 비우고 또 부딪힐 수 있게 했다... 흠..


그리고 마지막인 Up 이벤트. ReleaseMouseCapture() 를 해주고 다른 박스를 클릭할 수 있게 한다. 마우스 Move로 쥐고 있었던 박스(윗 그림에서 Box1)를 자기가 가야할 위치로 이동시킨다. 다른 잡다한 값들 역시 리셋시켜준다.

실버라이트 공부하면서 계속 느끼는건데, 알고리즘 진짜 싫어하는데 알고리즘 책 봐야겠다.. 개발자가 알고리즘 싫어한다는 말하면 돌맞는데.. 후후.


여튼 어정쩡 하게 실습은 끝.
물론 다른 소스는 거들떠 보지 않은 삽질의 결과이기 때문에 본 초보는 아주 만족한다. 시작이 반.


반응형
Comments