티스토리 뷰

Winform으로 개발할 경우에 다양한 컨트롤 중에 특정 컨트롤은 마우스 이벤트를 안받도록 해야할 때가 있다.

특히, 컨트롤의 Enable 속성을 False로 하지 않고 마우스 이벤트만 안받도록 해야하는 경우이다.


컨트롤의 Enable 속성을 False로 하면 라벨의 경우 글자 색이 회색으로 변하게 된다.



그래서 WPF는 IsHitTestVisible 이란 속성을 제공하는데, 이를 False로 설정할 경우 설정된 컨트롤은 마우스 이벤트를 받지 않는다. False로 설정된 해당 요소의 하위에 있는 요소에 마우스 이벤트가 전달되는 것이다.


색상도 변하지 않는다. 사용자 눈에 보이는 것은 그대로인데 마우스 이벤트만 안받는다.


그런데 윈폼의 경우 위 속성을 설정하는 방법이 없다.....


예를 들어...아래와 같은 사용자 정의 컨트롤이 있다고 생각하자.

이 사용자 정의 컨트롤이 마우스 드래그로 이동하는 기능을 갖춰야 한다면 일반적으로 회색 부분 ( 윈폼으로 말하자면 메인 폼 부분 )에 MouseMove 이벤트를 걸 것이다.


하지만, 라벨1, 2, 3 과 같은 부분에 마우스를 가져다 대고 드래그 하면 어떨까?


당연히 드래그 기능이 동작하지 않는다.


Winform에 IsHittestVisible 속성을 설정할 수 있다면 속성만 True에서 False로 바꿔주면 되겠지만 윈폼에서는 이 속성을 제공하지 않는다.


따라서 위와 같이 (사용자에게는 동일하게 보이면서) 마우스 이벤트만 받지 않는 컨트롤을 만드려면, 다음과 같은 번거로운(?) 작업을 해주어야 한다.


1. 프로젝트에 사용자 정의 컨트롤을 추가한다.


2. 만약 위와 같이 [마우스 이벤트를 받지 않는 라벨]을 만들어야 한다면 아래와 같이 상속 부분을 UserControl에서 Label로 변경하고 WndProc 함수를 오버라이드 한다.




//마우스 포커스를 받지 않게 하기 위해서 서브클래싱.
    public partial class myLabel : Label //UserControl 을 상속받지 않고, 필요한 클래스를 상속받음.
    {
        private const int WM_NCHITTEST = 0x84; //현재 마우스 커서의 위치가 윈도우의 어떤 부분에 있는지 조사할 때 먼저 보내는 메시지.
        private const int HTTRANSPARENT = -1;

        protected override void WndProc(ref Message message)
        {
            if (message.Msg == (int)WM_NCHITTEST) //만약 이 라벨에 WM_NCHITTEST 메시지가 전달되면
                message.Result = (IntPtr)HTTRANSPARENT; // 그대로 통과시킴.
            else
                base.WndProc(ref message);
        }
        /*
        ---------------------- DefwindowProc 의 리턴값 -------------------------------------
        HTBORDER 크기 조절이 불가능한 경계선 18
        HTBOTTOM 아래쪽 경계선 15
        HTTOP  위쪽 경계선
        HTBOTTOMLEFT 아래 왼쪽 경계선 16
        HTBOTTOMRIGHT 아래 오른쪽 경계선 17
        HTTOPLEFT 위 왼쪽  경계선 13
        HTTOPRIGHT 위 오른쪽 경계선 14
        HTLEFT  왼쪽 경계선 10
        HTRIGHT  오른쪽 경계선 11
        HTCAPTION 타이틀 바 2
        HTCLIENT  작업영역 1
        HTCLOSE  닫기 버튼 20
        HTSIZE  크기 변경 박스 4
        HTHELP  도움말 버튼 21
        HTHSCROLL 수평 스크롤 바 6
        HTVSCROLL 수직 스크롤바 7 
        HTMENU  메뉴 5
        HTMAXBUTTON 최대화 버튼 9
        HTMINBUTTON 최소화 버튼 8
        HTSYSMENU 시스템 메뉴 3
        HTTRANSPARENT 같은 스레드의 다른 윈도우에 가려진 부분 -1
        --------------------------------------------------------------------------------------
        */
    }

위의 설명과 같이 윈도우는 마우스가 어떤 컨트롤 위에 위치하는지 WM_NCHITTEST 이벤트를 보내서 리턴값을 보고 판단하게 된다.


message.Result = HTTRANSPARENT; 처럼 -1을 반환하게 되면 해당 요소의 하위 요소에 마우스 이벤트를 전달하게 되어 마우스 이벤트를 받지 않는 라벨 구현이 가능해 진다.


단점이 있다면

1. 윈폼 디자이너에서도 포커스를 받지 않게되어 위치를 지정하기 힘들다. 

컨트롤을 클릭하지 말고 컨트롤을 마우스로 범위를 지정하여 선택한 후 키보드로 움직이면 된다.


위 그림처럼 하면 라벨 1이 선택된다. 이후 키보드로 위치 지정


2. 이렇게 만든 라벨을 이용하려면 디자이너 도구상자에 추가해야 한다.

화면 디자인 하는 곳으로 가서, [도구상자] 에서 마우스 우클릭하여 [항목선택] -> [.Net Framework 구성요소] 선택

자신이 만든 [컨트롤 이름] 선택 후 확인 하면 도구상자에서 끌어다 놓을 수 있게 셋팅된다.


아래는 [myLabel] 이라는 사용자 정의 컨트롤을 추가하는 방법.



위처럼 작업한다면 사용자 눈에는 보이지만 마우스 이벤트는 받지 않는 ,, Enable 속성을 변경하는 것과는 다른 효과를 내게 된다.


이렇게 또 하나를 알아간다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함