[WinAPI] HCURSOR 사용법

[WinAPI] HCURSOR 사용법

오늘은 마우스 커서를 바꾸는 방법을 알아보겠습니다.

  1. 대화상자 내에서만 커서 바꾸는 법
  2. 컨트롤 위에 마우스가 있을 때만 바꾸는 법
  3. 대화상자 밖에서도 커서 바꾸는법

을 알아보겠습니다.

우선 그전에 아래 Cursor.zip 파일을 다운받아서 압축 해제 후 res 폴더에 넣어주세요.

그리고 리소스 뷰에서 3개의 커서 파일을 추가해줍니다.

각 리소스의 아이디는 색에 맞게 IDC_CURSOR_RED, IDC_CURSOR_GREEN, IDC_CURSOR_BLUE로설정합니다.

1. 대화상자 내에서만 커서 바꾸는 법
아래와 같이 버튼 하나를 만든 후 더블클릭으로 이벤트 처리 함수를 만들어줍니다.

헤더파일에 대화상자 내에 표시할 HCURSOR m_hCursorIn, 그리고 BOOL m_bMouseSet을 선언해 줍니다.

HCURSOR m_hCursorIn;	// 대화상자 내
BOOL m_bMouseSet;		// 플래그

OnInitDialog에 아래와 같이 코딩해줍니다.

m_hCursorIn = AfxGetApp()->LoadCursor( IDC_CURSOR_RED ); // 대화상자 내

아래와 같이 OnSetCursor를 만들어 줍니다.

OnSetCursor 내부에 아래와 같이 코딩해줍니다.

BOOL CCursorTestDlg::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message )
{
	// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
	if ( m_bMouseSet )
	{
		::SetCursor( m_hCursorIn );
		return TRUE;
	}

	return CDialogEx::OnSetCursor( pWnd, nHitTest, message );
}

위에서 만든 버튼 이벤트 처리 함수에 아래와 같이 코딩해 줍니다.

void CCursorTestDlg::OnBnClickedButton1()
{
	m_bMouseSet = !m_bMouseSet;	
}

실행시켜서 확인해 봅니다.

이 마우스는 대화상자 바깥을 나가면 원래대로 돌아옵니다.

2. 컨트롤 위에 마우스가 있을 때만 바꾸는 법
헤더파일에 HCURSOR m_hCursorMouseOn을 선언합니다.

HCURSOR m_hCursorMouseOn;	// 마우스 버튼위에 올렸을 때

아래와 같이 버튼 하나를 더 추가하고 더블 클릭을 눌러 이벤트 처리 함수를 만듭니다.

OnInitDialog에 아래와 같이 추가로 코딩합니다.

m_hCursorIn = AfxGetApp()->LoadCursor( IDC_CURSOR_RED );	// 대화상자 내

m_hCursorMouseOn = AfxGetApp()->LoadCursor( IDC_CURSOR_GREEN );	// 마우스가 올라갔을 때

위에서 만든 버튼 이벤트 처리 함수에 아래와 같이 코딩합니다.

void CCursorTestDlg::OnBnClickedButton2()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	SetClassLongW( ::GetDlgItem(this->GetSafeHwnd(), IDC_BUTTON2), GCL_HCURSOR ,(LONG)m_hCursorMouseOn);
}

실행 시켜 확인해 봅니다.


3. 대화상자 밖에서도 커서 바꾸는법

버튼을 하나 더 추가합니다.

헤더파일에 기존 커서를 저장할 HCURSOR m_hCursorPre와 바꿀 커서 HCURSOR m_hCursorOut을 선언합니다.

HCURSOR m_hCursorPre;	// 기존 모양
HCURSOR m_hCursorOut;	// 대화상자 바깥

OnInitDialog에 아래와 같이 초기화를 합니다.

m_hCursorIn = AfxGetApp()->LoadCursor( IDC_CURSOR_RED );	// 대화상자 내

m_hCursorMouseOn = AfxGetApp()->LoadCursor( IDC_CURSOR_GREEN );	// 마우스가 올라갔을 때

m_hCursorPre = CopyCursor( LoadCursor( NULL, IDC_ARROW ) );	// 기존 커서
m_hCursorOut = (HCURSOR)LoadImageW(				// 바깥에서 사용할 커서
	AfxGetInstanceHandle(),
	MAKEINTRESOURCE( IDC_CURSOR_BLUE ),
	IMAGE_CURSOR,
	32, 32,
	LR_DEFAULTCOLOR );

위에서 만든 버튼을 더블 클릭하여 이벤트 처리 함수를 만든 후 아래와 같이 코딩합니다.

void CCursorTestDlg::OnBnClickedButton3()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	HCURSOR hcursor = CopyCursor( m_hCursorOut );
	::SetSystemCursor( hcursor, 32512/*OCR_NORMAL*/ );
}

::SetSystemCursor를 사용하면 첫번째 인자로 들어간 HCURSOR는 소멸되니 항상 CopyCursor로 복사를 해서 SetSystemCursor에 사용 합니다.

::SetSystemCursor로 마우스를 만들어주면 대화상자가 종료되어도 그 상태로 유지하므로 대화 상자가 소멸 할 때 원래 상태로 복귀하게 OnDestroy을 선언합니다.

그리고 아래와 같이 코딩합니다.

void CCursorTestDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	// TODO: 여기에 메시지 처리기 코드를 추가합니다.
	::SetSystemCursor( m_hCursorPre, 32512/*OCR_NORMAL*/ );
	::DestroyCursor( m_hCursorOut );
	::DestroyCursor( m_hCursorIn );
	::DestroyCursor( m_hCursorMouseOn );
}

그리고 실행하여 확인합니다.

참고로 ::SetSystemCursor에서 32512는 기본 마우스 모양(IDC_ARROW)에 대한 값으로 다른 상태일 경우에 커서를 바꾸고 싶으시면 WinUser.h을 참고 하셔서 값을 넣어주시면 됩니다.

#define IDC_ARROW           MAKEINTRESOURCE(32512)
#define IDC_IBEAM           MAKEINTRESOURCE(32513)
#define IDC_WAIT            MAKEINTRESOURCE(32514)
#define IDC_CROSS           MAKEINTRESOURCE(32515)
#define IDC_UPARROW         MAKEINTRESOURCE(32516)
#define IDC_SIZE            MAKEINTRESOURCE(32640)  /* OBSOLETE: use IDC_SIZEALL */
#define IDC_ICON            MAKEINTRESOURCE(32641)  /* OBSOLETE: use IDC_ARROW */
#define IDC_SIZENWSE        MAKEINTRESOURCE(32642)
#define IDC_SIZENESW        MAKEINTRESOURCE(32643)
#define IDC_SIZEWE          MAKEINTRESOURCE(32644)
#define IDC_SIZENS          MAKEINTRESOURCE(32645)
#define IDC_SIZEALL         MAKEINTRESOURCE(32646)
#define IDC_NO              MAKEINTRESOURCE(32648) /*not in win3.1 */
#if(WINVER >= 0x0500)
#define IDC_HAND            MAKEINTRESOURCE(32649)
#endif /* WINVER >= 0x0500 */
#define IDC_APPSTARTING     MAKEINTRESOURCE(32650) /*not in win3.1 */
#if(WINVER >= 0x0400)
#define IDC_HELP            MAKEINTRESOURCE(32651)