상세 컨텐츠

본문 제목

Visual Studio c++ MFC 마우스 입력 이벤트 관련

본문

반응형

 

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

출처: http://hatti.tistory.com/entry/MFC-Dialog-PreTranslateMessage

 

 

특정 컨트롤러나 Dialog에 이벤트를 주고 싶다. 하면 그냥 이벤트 등록하면 간단한 일이다. 하지만 특정 부분에 대해서, 세세하게 이벤트를 달아주고 싶다면, 이 방법을 써보자.

 



PreTranslateMessage

 


MSDN -
Override this function to filter window messages 

before 

they are dispatched to the Windows functions TranslateMessage and DispatchMessage The default implementation performs accelerator-key translation, so you must call the CWinApp::PreTranslateMessage member function in your overridden version.

before 이하가 중요하다. - 영어시간 아닙니다 (웃음) 

TranslateMessage, DispatchMessage 에 보내지기 전에 걸러내기 위해 작성된 함.수.란다.

맴버를 보면 

virtual BOOL PreTranslateMessage(   MSG* pMsg );

인데, pMsg는 또 포인터 구조체 란다.
 

pMsg
  A pointer to a MSG structure that contains the message to process.

저는 MSDN을 신뢰합니다.

 

 

그래서,, MSG 구조체를 살펴보면,

 

typedef struct tagMSG 
{     
    // msg          
    HWND hwnd;         
    UINT message;         
    WPARAM wParam;         
    LPARAM lParam;         
    DWORD time;         
    POINT pt; 
} MSG;

 

hWnd
  Identifies the window whose window procedure receives the message.

message
  Specifies the message number.

wParam
   
Specifies additional information about the message. The exact meaning depends on the value of the message member.

lParam
   
Specifies additional information about the message. The exact meaning depends on the value of the message member.

time
  
Specifies the time at which the message was posted.

pt
  
Specifies the cursor position, in screen coordinates, when the message was posted.



한글로 봅시다.

hwnd : 메시지를 받는 윈도우 프로시져를 가진 윈도우의 식별자. (누구꺼냐고)
message : 메시지 번호는 윈도우 메시지들. WM형제들
wParamlParam : 메시지 전달인자 Virtual key codes 
time :  메시지 발생 시간
pt : 메시지가 발생한 지점, 그러니까 좌표계, point형이니까

 



예)

BOOL CsunClientDlg::PreTranslateMessage(MSG* pMsg) 
{ 	
   // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다. 		
   if( pMsg->hwnd == m_edtUserId.GetSafeHwnd() && // 이 이벤트가 일어난 곳이 m_edtUserId라는 컨트롤이고 		
   pMsg->message == WM_KEYDOWN && // 무슨 키가 눌러졌는데  		
   pMsg->wParam == VK_RETURN) // 그 키가 엔터키이면 	
   {
   
   } 	
   
   return false; 
   
   //CDialog::PreTranslateMessage(pMsg);    
}

 

 

※ GetSafeHwnd()는 자신의 핸들을 가져오는 메소드 입니다.
※ message는 키보드, 마우스 다 가능합니다. 

 

이런 식으로 작성하면 어디에서든 원하는 이벤트를 가져올 수 있다.

자 이제 컨트롤에 이벤트를 달아보자 :D 
와아아아아아와와오아와아아ㅗ아ㅗ아ㅗ아와아아앙아아오아ㅗ아와오아 (퍽 

ㅇ>-< 

 


출처: http://hatti.tistory.com/entry/MFC-Dialog-PreTranslateMessage [네 보기 좋다하여 꺾지 말아라]

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: http://blog.naver.com/PostView.nhn?blogId=1004kiwoo&logNo=60128691649

 

BOOL CTest1Dlg::PreTranslateMessage(MSG* pMsg) 
{  

//이함수 아시죠? 위저드로 보면 있을껍니다. 없으시면 만드세요.

//프로그램이 돌아갈때 모든 메시지가 거쳐가는 곳이지요..
 // TODO: Add your specialized code here and/or call the base class
 CRect rect; //일단 선언

 

  if(pMsg->message == WM_LBUTTONDOWN) 
 {  //메시지가 LBUTTONDOWN일때 실행

 

     CButton *pButton = (CButton *)GetDlgItem(IDC_BUTTON2);

     //해당버튼 버튼변수에 넣고
     pButton->GetWindowRect(rect); 

     //버튼위치 가져오기 입니다. 
     if(rect.PtInRect(pMsg->pt))

     //위에 구한 버튼위치와 마우스위치가 일치하면 실행
     {
       *******여기에 님이 구현하실꺼 쓰세요********
     }        
     
 }

  if(pMsg->message == WM_LBUTTONUP) 

  //마찬가지로^^ UP잡아서 처리해주고 싶은거 하시면되겠죠?

  //여기서  KillTimer 하시면 되겠네요..

 그럼 도움이 되시길요

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: http://frostguy.tistory.com/33

 

Static Control 에서의 마우스 이벤트 처리
Study/MFC / 2009.06.24 16:26

 

BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)  
{ 	
	// TODO: Add your specialized code here and/or call the base class 	
    if (pMsg->message == WM_LBUTTONDOWN) 	
    { 		
    	if (pMsg->hwnd ==  GetDlgItem(IDC_STATIC_TEXT)->GetSafeHwnd()) 			
        {
        	AfxMessageBox("Left Button Down"); 	
        } 	
        else if (pMsg->message == WM_RBUTTONDOWN) 	
        { 		
        	if (pMsg->hwnd == GetDlgItem(IDC_STATIC_TEXT)->GetSafeHwnd())
            { 			
            	AfxMessageBox("Right Button Down"); 	
            } 	
            
            return CDialog::PreTranslateMessage(pMsg); 
        }
    }    
    
    
}

 

 

PreTranslateMessage 에서 현재의 윈도우에서 마우스위치 캐치



xPos = GET_X_LPARAM(pMsg->lParam);  yPos = GET_Y_LPARAM(pMsg->lParam);

 

 

 

 

=======================

=======================

=======================

 

 

 

 



[MFC]Static 컨트롤에는 마우스 이벤트는 클릭 좌우 구분을 못한다.

 
Static에서 발생한 클릭 이벤트의 경우 LBUTTON DOWN만 인식되는거 같음
RBUTTON도 인식하도록 변경도 해야함.

BOOL CArrayImageDlg::PreTranslateMessage(MSG* pMsg) //클래스에서 재정의에 들어가서 생성
{
      __bLBtnDown = false;  //UP을 별도로 인식 안해도 되도록
     __bRBtnDown = false;

     if(pMsg->message == WM_LBUTTONDOWN)
     {
          if(pMsg->hwnd == GetDlgItem(IDC_STATIC_IMAGE)->GetSafeHwnd())
           __bLBtnDown = true;
     }
     if(pMsg->message == WM_RBUTTONDOWN)
     {
          if(pMsg->hwnd == GetDlgItem(IDC_STATIC_IMAGE)->GetSafeHwnd())
          {
               __bRBtnDown = true;
               OnStnClickedStaticImage(); //R버튼은 클릭 이벤트를 직접 호출(LBUTTON에서는 두번 호출하게 되므로 PASS
          }
     }
 return CDialog::PreTranslateMessage(pMsg);
}

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: http://startcoding.tistory.com/82

 

6장: 마우스 입력

 

1. 마우스 메시지

윈도우에서 중요한 입력도구: 마우스

마우스 버튼은 기본적으로 좌, 우 그리고 중간에 휠이 존재.(요즘은 터치도 있다 ^^)

매번 하던 대로 MFC 응용 프로그램 프로젝트를 생성.

 

마우스 이동 시:

마우스 움직일 때마다 발생 - OnMouseMove

Point: 좌표

RedrawWindow: 윈도우 다시 그리기

윈도우를 그리는 OnPaint 함수를 추가해서

텍스트로 현재 마우스 좌표를 알려주는 코드를 삽입

마우스를 움직이면 좌표로 알려 줌

 

마우스 휠:

휠과 관련된 OnMouseWheel 함수를 보자

zDelta 값은 휠을 움직이는 속도를 알려준다.

디버그 모드로 보면 zDelta 값이 지정된 것을 확인할 수 있다

 

2. 마우스 움직임의 조합

 

  • 마우스 더블클릭 시:

더블클릭 시 사용할 OnLButtonDblClk

알림 창에서 TEST 문자열이 나타나도록 만듦

더블클릭 시 TEST 창 나타남

 

주요 마우스 이벤트 정리:

  • WM_MOUSEMOVE: 마우스 움직임에 따라 발생하는 메시지
  • WM_LBUTTONDOWN: 왼쪽 버튼을 눌렀을 때 발생
  • WM_LBUTTONUP: 누르고 떼었을 때 발생
  • WM_MOUSEWHEEL: 마우스 휠을 위/아래로 움직일 때 발생
  • WM_LBUTTONDBLCLK: 더블 클릭했을 때 발생

 

새로운 프로젝트 생성:

마우스 콤비네이션을 뜻하는 MouseCombi 프로젝트 생성

 

중단점 설정:

실제로 마우스 동작을 알아 보기 위해서

  • 마우스 누름
  • 누른 버튼 뗌
  • 더블 클릭

에 대해 각각 중단점을 설정

디버그 모드로 보면 클릭, 그리고 땠을 때의 결과가 나타남.

물론 더블클릭도 나타남.

뷰윈도우의…

멤버변수로 문자열 좌표 기억하는 것과 드래그 시작 여부를 구분하는 변수를 선언

함수 생성자에 문자열 출력할 좌표와 드래그 여부를 false로 설정.

드래그 여부에 따라 문자가 ---- 에서 DRAG 로 바뀌고, 그 밑에는 실제로 드래그에 쓰일 '내 컴퓨터' 문자를 생성

이렇게 생성 됨(아직 드래그 하는 중이 아니라서 ---- 와 같은 모양)

마우스 왼쪽 버튼을 눌렀을 때 드래그가 시작되어야 하므로 OnLButtonDown에 내용을 넣는다.

실제 드래그가 될 지점은 사각형 공간이므로 위에서 생성했던 '내 컴퓨터' 텍스트의 위치를 기준으로 사각형 공간을 생성해 주고, 이 안에서 마우스가 클릭되면 드래그가 시작(true)된다고 프로그램에 알려줌

실제로 테스트 해 보면 DRAG 문자로 바뀜

그리고 마우스 버튼이 놓아졌을 때 드래그를 멈춰야 하기 때문에 OnLButtonUp 함수에서 이를 설정해 줌.

마지막으로 놓은 위치에서 텍스트가 멈춰(그 자리에 위치)야 하기 때문에 현재 point 좌표를 텍스트의 좌표로 넘겨 줌

내 컴퓨터를 드래그 해서 놓은 모습. 그 자리에 텍스트가 멈춰선 것을 확인할 수 있다

하지만 DRAG 중에 이 텍스트가 따라다니지 않아 보기가 좋지 않다. 아래에서 이를 구현한다.

마우스가 움직일 때 발생하는 메시지를 핸들링하는 OnMouseMove 함수 선택

마우스가 드래그 될 때 좌표를 저장해 준다

(플래그는 초기화 하지 않아서 드래그 중인 상황이 계속 유지된다)

 

 

 

반응형

 

 

 

728x90

 

 

 

드래그 중에 마우스를 따라서 내 컴퓨터 텍스트가 따라 다니게 됨

드래그 앤 드롭의 ABC:

  1. WM_LBUTTONDOWN (클릭시작) – 위치 선정
  2. WM_MOUSEMOVE (마우스 이동) – 이동
  3. WM_LBUTTONUP (왼쪽 버튼에서 손가락을 뗌) – 위치 선정

 

3. 마우스 이벤트의 추적

 

지금까지 한 실습에는 버그 존재: 드래그 시 윈도우 벗어나면 제 역할을 못함 (텍스트에서 마우스를 떼고 있어도 눌린 것처럼 반응)

왜 발생했을까?

Mouse: 윈도우 특정적이다. 윈도우 범위를 벗어나면 해당 윈도우의 메시지를 받지 못한다.(마우스 이동하고, 뗀 것을 인식하지 못한다)

해결 방법은?

마우스 캡쳐(capture): 마우스 메시지를 윈도우 범위 밖에서 받을 수 있지만 버튼이 손가락에서 떼어졌을 때 좌표 계산을 잘못하면 그 개체가 다시 선택할 수 없는 상태로 변할 수 있다. (완전한 해결책이 아니라는 뜻이다.)

윈도우 범위를 벗어났을 때 적절한 처리를 해 주는 것을 고려하는 것이 좋다.

예를 들어: 왼쪽으로 갔을 때 사라졌다 -> MouseMove시 point 값이 음수일 때 적용하지 않으면 됨

 

 

왼쪽 버튼이 눌러졌을 때 캡쳐 시작

 

 

마우스 왼쪽 단추를 놓았을 때 캡쳐 해제

 

 

 

마우스가 범위를 벗어나도 캡쳐에 의해 계속 인식되고 있음을 확인할 수 있다

하지만 위에서 말했던 단점은 그대로 존재한다.

화면 왼쪽 바깥에 나갔을 때 강제로 x좌표를 0으로 함으로써 문제를 막는 코드

드래그 앤 드롭시 내 컴퓨터 텍스트가 더 이상 왼쪽으로 가지 않게 되어 컨트롤하기 수월하다

 

트래킹 윈도우 생성:

클래스 추가

MFC 클래스 추가

CTrackWnd 클래스 추가

클래스뷰에 등록된 것을 확인 가능

WM_CREATE 메시지를 받아올 OnCreate 메시지 핸들러 함수 추가

트래킹에 사용될 윈도우 생성. STATIC 윈도우에서 메시지를 캐치하려면 SS_NOTIFY 를 사용한다.

작은 차일드 윈도우가 생성된 것을 확인. 여기서 마우스 트래킹(마우스 올라온 것을 확인) 할 예정.

차일드윈도우 안에서 마우스가 움직이면 동작할 OnMouseMove 함수 추가

마우스가 움직이면 트래킹 중이라는 텍스트 메시지를 내보낸다.

실제로 차일드윈도우 안에서 마우스를 움직이면 Tracking 이라는 표시 나옴

하지만 마우스가 차일드 윈도우를 벗어나도 여전히 트래킹 중이라고 나옴. 수정 필요

마우스가 나갔을 때 알아차리려면(원래대로 돌아오려면) 마우스가 나가는 시점을 등록해 줘야 함.

차일드 클래스의 멤버 함수로 트래킹 중임을 구분하는 m_bTrack 을 선언

트래킹윈도우(차일드 윈도우) 생성자 함수 추가

윈도우 생성 시 트래킹 바로 시작할 필요 없기에 트래킹 여부 false 값을 넣어 줌

마우스가 트래킹 상태가 아니면(!m_bTrack)

트래킹을 시도하면 되겠죠.

={0} : 초기화

dwFlags = TME_LEAVE : 윈도우 영역을 벗어나면 WM_MOUSELEAVE를 전달해 달라는 뜻

m_hWnd: 윈도우의 핸들을 줘야 함

::_Track… : 함수 호출

트래킹에 성공하면 위 함수(TrackMouseEvent)가 True를 리턴함

트래킹에 성공하면(m_bTrack) 트래킹 상태를 표시.

마우스가 바깥으로 벗어나면

텍스트를 원래대로 TRACK TEST로 돌려 놓고, m_bTrack 상태를 false로 설정.

영역 안에서는 트래킹되고,

벗어나면 초기 상태(TRACK TEST 텍스트)로 돌아옴

 

결론:

위 사진에서 '실제'로 휴지통이 존재할까? 아니다. 단지 사용자들이 인터페이스 측면에서 접근하기 쉽도록 저 자리에 휴지통처럼 생긴 아이콘을 배치했을 뿐이다.

"있어 보인다" 는 게 정말 정말 중요. (User Interface 측면에서)

실제와는 상관이 전혀 없더라도, 그렇게(눈으로 볼 수 있게) 보여야 함!!

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

출처: http://www.gpgstudy.com/forum/viewtopic.php?t=15914

 



MFC질문: 버튼을 누르는 동안 동일한 메시지가 발생하게 하려면?
인용
전체글 글쓴이: 비회원 » 2007-05-15 23:06

MFC 입문자라서 아직 모르는 게 많습니다.

Visual C++.Net 2003입니다. 

버튼 위에서 마우스 오른쪽 버튼을 클릭하면 이벤트 처리기 추가가 나옵니다만

"버튼을 누르고 있는 동안 동일한 메시지를 반복해서 발생시키는 것"은 직접 지원하지는 않는 것 같습니다.

반응 할 수 있는 메시지가 BN_CLICKED, BN_DOUBLECLICKED, BN_KILLFOCUS, BN_SETFOCUS

BN_HOTITEMCHANGE, NM_THEMECHANGED 뿐입니다.



"버튼을 누르고 있는 동안 동일한 메시지를 반복해서 발생시키는 것"을 하기 위해서는 어떤 식으로

작성해야 할 지 자료를 좀 알려주셨으면 합니다.
상위

비회원

인용
전체글 글쓴이: 비회원 » 2007-05-16 00:19

switch( msg )
{
case 버튼 다운 :
SetTimer(hWnd, 1, 1000, NULL);
SendMessage(hWnd, WM_TIMER, 1, 0);
break;
csae 버튼 업:
KillTimer(hWnd, 1);
break;
case WM_TIMER:
if(wParam == 1)
{
// 버튼 업 전까지는 1초마다 한번씩 들어오겠죠?
}
break;
}


상위

비회원
win32에서 하는 법이 아니라 MFC에서 하는 방법을 알려주세요.
인용
전체글 글쓴이: 비회원 » 2007-05-16 11:30

win32에서 하는 방법은 알겠는데 MFC 로 특정 버튼이 눌린 동안만 메시지를 발생시키는 법을 알았으면 합니다.

나름데로 한가지 방법을 알아내기는 했는데 이게 전형적인 방법인지도 모르겠습니다.

devpia를 검색해도 모르겠고 codeproject에서는 적당한 질문 문구가 아닌지 검색이 되지 않네요.


상위

비회원

인용
전체글 글쓴이: 비회원 » 2007-05-16 11:51

MFC에서는 OnRButtonDown() 에서
SetTimer(hWnd, 1, 1000, NULL); 
SendMessage(hWnd, WM_TIMER, 1, 0); 
이부분으로 타이머를 발생시키고

OnRButtonUp() 에서
KillTimer(hWnd, 1);
하시고

마지막으로
OnTimer() 에서
하실 작업 하시면 될듯 하네요
상위

nenene
전체글: 8
가입일: 2006-08-21 17:10
-_-
인용
전체글 글쓴이: nenene » 2007-05-16 13:00

BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.

if( GetDlgItem(IDC_BUTTON1)->GetSafeHwnd() == pMsg->hwnd )
{
if( pMsg->message == WM_LBUTTONDOWN )
{
TRACE("down\n");
}
else if( pMsg->message == WM_LBUTTONUP )
{
TRACE("up\n");
}
}

return CDialog::PreTranslateMessage(pMsg);
}

메세지는 알아서..
상위

비회원
고맙습니다.
인용
전체글 글쓴이: 비회원 » 2007-05-16 15:00

고맙습니다.

제가 생각해 냈다고 한 것도

결국 이것과 동일한 것인데
MFC에서는 OnRButtonDown() 에서 
SetTimer(hWnd, 1, 1000, NULL); 
SendMessage(hWnd, WM_TIMER, 1, 0); 
이부분으로 타이머를 발생시키고 

OnRButtonUp() 에서 
KillTimer(hWnd, 1); 
하시고 

마지막으로 
OnTimer() 에서 
하실 작업 하시면 될듯 하네요

이것이 더 제가 기대하던 것에 가까운 코드입니다.

-_- 올려짐: 2007-05-16 13:00


이 코드가 기대했던 것에 아주 잘 들어 맞는 코드입니다. 
BOOL CTestDlg::PreTranslateMessage(MSG* pMsg) 
{ 
// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다. 

if( GetDlgItem(IDC_BUTTON1)->GetSafeHwnd() == pMsg->hwnd ) 
{ 
if( pMsg->message == WM_LBUTTONDOWN ) 
{ 
TRACE("down\n"); 
} 
else if( pMsg->message == WM_LBUTTONUP ) 
{ 
TRACE("up\n"); 
} 
} 

return CDialog::PreTranslateMessage(pMsg); 
} 

메세지는 알아서..

올려주신 분들께 감사드립니다.

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

반응형


관련글 더보기

댓글 영역