210 likes | 380 Views
Windows Programming 제대로 배우기. Chapter 3. Mouse Event. 학습 목표. 마우스 대한 이벤트를 컨트롤 하는 방법에 대해서 설명. 마우스의 클라이언트 영역. - 마우스가 클릭하였을 때 마우스에 대한 메시지가 발생되는데 클라이언트 영역과 비클라이언트 영역에 분리되어 다르게 나타남 클라이언트 영역이란 윈도우 타이틀바와 외곽선을 제외한 즉 실지로 WM_PAINT 메시지에 의해서 그래픽을 출력하는 영역 이 영역에서 마우스가 움직이거나 클릭하였을 경우에 발생하는 메시지 리스트.
E N D
Windows Programming제대로 배우기 Chapter 3. Mouse Event
학습 목표 마우스 대한 이벤트를 컨트롤 하는 방법에 대해서 설명
마우스의 클라이언트 영역 - 마우스가 클릭하였을 때 마우스에 대한 메시지가 발생되는데 클라이언트 영역과 비클라이언트 영역에 분리되어 다르게 나타남 • 클라이언트 영역이란 윈도우 타이틀바와 외곽선을 제외한 즉 실지로 WM_PAINT 메시지에 의해서 그래픽을 출력하는 영역 • 이 영역에서 마우스가 움직이거나 클릭하였을 경우에 발생하는 메시지 리스트
마우스 예제 내용 WM_LBUTTONDOWN메시지를 이용하여 마우스가 클릭되었을 때 몇 번 클릭되었는가를 나타내는 프로그램 예제 설명 • switch문에 WM_LBUTTONDOWN을 설정하여 좌측 마우스 버튼이 눌려졌을 때 마우스 이벤트를 얻음 case WM_LBUTTONDOWN: • case WM_LBUTTONDOWN: count++; break;
#include <stdio.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static int count; char temp[80]; switch(uMsg) { case WM_CREATE : count = 0; break; case WM_PAINT : hdc = BeginPaint(hWnd, &ps); count++; sprintf(temp, "Count = %d", count); TextOut(hdc, 50, 50, temp, strlen(temp)); EndPaint(hWnd, &ps); break; case WM_DESTROY : PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }
재출력의 필요성 • 마우스를 눌러도 count가 바뀌지 않음 (윈도우를 움직이면 count가 변경됨) • 무엇이 문제인가? • 윈도우에서는 InvalidateRect함수를 사용하여 윈도우를 다시 그려야한다는 메시지를 발생시켜야 함. • InvalidateRect함수는 WM_PAINT메세지를 해당 윈도우에 보낸다.
InvalidateRect 함수 InvalidateRect( HWND hWnd , // 윈도우 핸들 - 식별자 CONST RECT *lpRect, BOOL bErase); // 영역 부분이 NULL이면 윈도우 전체 영역이 다시 그려지게 됨
#include <stdio.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static int count; char temp[80]; switch(uMsg) { case WM_CREATE : count = 0; break; case WM_PAINT : hdc = BeginPaint(hWnd, &ps); sprintf(temp, "Count = %d", count); TextOut(hdc, 50, 50, temp, strlen(temp)); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN : count++; InvalidateRect(hWnd, NULL, TRUE); break; case WM_RBUTTONDOWN : count--; InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY : PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }
Event Driven과 Programming Style • Event-Driven에서 제각각 발생하는 메시지를 가지고 처리하는 프로그래밍 방식 • 데이터를 중심으로 어디선가 누군가에 의해 (Event) 변경이 되면, 즉각 재출력을 하여 다시 그 결과를 반영하도록 함 • 윈도우 프로그램에서는 데이터를 중심으로 설계 필요
#include <stdio.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static int count; char temp[80]; switch(uMsg) { case WM_CREATE : count = 0; break; case WM_PAINT : hdc = BeginPaint(hWnd, &ps); sprintf(temp, "Count = %d", count); TextOut(hdc, 50, 50, temp, strlen(temp)); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN : count++; InvalidateRect(hWnd, NULL, TRUE); break; case WM_RBUTTONDOWN : count--; InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY : PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } 데이타변경 데이터 출력
Data Toggling • Toggle 이란? • 한번 누르면 켜지고 다시 한번 누르면 꺼지는 방식 • 프로그램에서는 자주 특정 변수를 일정한 방법으로 Toggle시켜 사용함
기본적인 Toggle 방법 • 1, 0 Toggle int flag = 1; flag = 1-flag; // flag = !flag; • 1, -1 Toggle int flag = 1; flag = flag*-1; // flag *= -1; • 0,1,2를 순차적으로 반복하는 Round Toggle int flag = 0; flag++; flag %= 3;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; char temp[80]; static int m_bFlag; switch(uMsg) { case WM_CREATE : m_bFlag = 1; break; case WM_PAINT : hdc = BeginPaint(hWnd, &ps); if(m_bFlag) strcpy(temp, "Toggle"); else strcpy(temp, ""); TextOut(hdc, 100, 100, temp, strlen(temp)); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN : m_bFlag = !m_bFlag; InvalidateRect(hWnd, NULL, TRUE); break; case WM_RBUTTONDOWN : break; case WM_DESTROY : PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } 데이타변경 데이터 출력
마우스 예제 • 화면 중앙에 자기가 원하는 텍스트 스트링을 나타낸 후 마우스 왼쪽 버튼을 누르면 글자를 왼쪽으로, 오른쪽 버튼을 누르면 글자를 오른쪽으로 이동하는 프로그램 작성 • 힌트 : TextOut 함수의 좌표를 이용함
// 필요 데이터 선언 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static char m_Str[80]; static POINT m_Point; static RECT m_Bound; int chSize = 8; switch(uMsg) { case WM_CREATE : strcpy(m_Str, "Moving Str"); GetClientRect(hWnd, &m_Bound); m_Point = CenterPoint(m_Bound); m_Point.x -= (strlen(m_Str)*chSize)/2; break; case WM_PAINT : hdc = BeginPaint(hWnd, &ps); TextOut(hdc, m_Point.x, m_Point.y, m_Str, strlen(m_Str)); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN : m_Point.x -= 20; InvalidateRect(hWnd, NULL, TRUE); break; case WM_RBUTTONDOWN : m_Point.x += 20; InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY : PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } // 윈도우 타이틀바를 제외한 전체 영역을 Client Area 라고 하는데, 이 영역에 관한 정보를 돌려주는 함수 // 적절한 초기화 // 화면 출력 // 마우스 이벤트 처리
POINT CenterPoint(RECT& r) { POINT p; p.x = (r.left + r.right) /2; p.y = (r.top + r.bottom) /2; return p; }
마우스 파라미터 lParam - 마우스가 눌려졌을 경우에 어느 부분이 눌려졌다는 정보를 기록하는 변수 • 32비트 LONG형 • 마우스 정보를 입력하여 정보를 알려주게 됨 • 상위 16비트 : Y 좌표 • 하위 16비트 : X 좌표 LOWORD, HIWORD • 32비트를 16비트로 나누어주는 함수 int y=HIWORD(lParam) int x=LOWORD(lParam)
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; char temp[80]; char *buttondata[4]={"안눌림 ","좌측버튼","우측버튼","양쪽눌림"}; POINT point; switch (iMsg) { case WM_CREATE : return 0 ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; EndPaint (hwnd, &ps) ; return 0 ;
case WM_LBUTTONUP: point.x=LOWORD(lParam); point.y=HIWORD(lParam); wsprintf(temp,"좌측버튼놓음:%04d : %04d", point.x,point.y); hdc=GetDC(hwnd); TextOut(hdc,0,40,temp,strlen(temp)); ReleaseDC(hwnd,hdc); break; case WM_RBUTTONDOWN: point.x=LOWORD(lParam); point.y=HIWORD(lParam); wsprintf(temp,"우측버튼눌림:%04d : %04d", point.x,point.y); hdc=GetDC(hwnd); TextOut(hdc,0,60,temp,strlen(temp)); ReleaseDC(hwnd,hdc); break; case WM_LBUTTONDOWN: //포인트 구조체에 좌표 정보를 넣는다. point.x=LOWORD(lParam); point.y=HIWORD(lParam); //temp에 위치를 넣고 출력 wsprintf(temp,"좌측버튼눌림:%04d : %04d", point.x,point.y); //DC를 받고 문자열을 출력한다. hdc=GetDC(hwnd); TextOut(hdc,0,20,temp,strlen(temp)); ReleaseDC(hwnd,hdc); break;
case WM_MOUSEMOVE: point.x=LOWORD(lParam); point.y=HIWORD(lParam); wsprintf(temp,"키눌림:%s 위치:%04d : %04d", buttondata[wParam],point.x,point.y); hdc=GetDC(hwnd); TextOut(hdc,0,0,temp,strlen(temp)); ReleaseDC(hwnd,hdc); break; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } case WM_RBUTTONUP: point.x=LOWORD(lParam); point.y=HIWORD(lParam); wsprintf(temp,"우측버튼놓음:%04d : %04d", point.x,point.y); hdc=GetDC(hwnd); TextOut(hdc,0,80,temp,strlen(temp)); ReleaseDC(hwnd,hdc); break;