프로그래밍/MFC

MFC 마우스 정보와 커서관리

에어버스 2016. 6. 18. 11:20

- 마우스 정보

::GetSystemMetrics(int nIndex);

<nIndex>

nIndex 의미 
 SM_CMOUSEBUTTONS   마우스 버튼 개수 리턴, 마우스 없으면 0 리턴
 SM_MOUSEPRESENT   마우스의 설치 여부를 TRUE 또는 FALSE로 리턴 
 SM_SWAPBUTTON   왼쪽과 오른쪽 버튼의 의미가 바뀌었으면 TRUE 리턴 
 SM_MOUSEWHEELPRESENT    휠 마우스이면 TRUE 리턴

- 커서 바꾸기

HCURSOR SetCursor(HCURSOR hCursor);

<hCursor>

앞으로 사용할 커서를 나타내는 커서 리소스를 가리키는 핸들

 

- WM_SETCURSOR 메시지 

OS는 Client영역(View)에 마우스 포인터가 들어올때 WM_SETFOCUS 메시지 받고, 나갈때 WM_KILLFOCUS 받음
커서 모양을 바꿀 필요가 있으면 WM_SETCURSOR 메시지에서 처리한다.
CWinApp::LoadStandardCursor() : OS에서 제공하는 마우스 커서를 선택
CWinApp::LoadCursor() : 사용자가 만든 마우스 커서를 선택

CWinApp 내부 함수가 아닌 다른 곳에서 CWinApp 내부 함수호출하려면 AfxGetApp() 을 이용하면 된다.

- 사용자 정의 마우스 커서 그리기

바탕화면과 투명색/반전색 선택 가능하고 핫스팟은 마우스 커서의 위치를 지정한다. 위 그림에서는 반전색과 핫스팟을 마우스 커서 그림의 중앙을 선택한다.

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
32
33
34
35
36
37
void CMFCApplication2View::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    dc.SelectStockObject(LTGRAY_BRUSH);
    dc.Rectangle(100100300300);
}
 
BOOL CMFCApplication2View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (nHitTest == HTCLIENT)
    {
        CPoint point;
        ::GetCursorPos(&point);
        ScreenToClient(&point);
        CRect rect(100100300300);
        if (rect.PtInRect(point)// 마우스 커서가 사각형안에 있는지 검사
            SetCursor(AfxGetApp()->LoadCursorW(IDC_CURSOR1)); // 사용자 정의 커서
        else
            SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); // 시스템 커서
        return TRUE;
    }
    return CView::OnSetCursor(pWnd, nHitTest, message);
}
 
void CMFCApplication2View::OnLButtonDown(UINT nFlags, CPoint point)
{
    CRect rect(100100300300);
    ClientToScreen(&rect);
    ::ClipCursor(&rect); // 카우스 커서 이동을 사각형 안으로 제한
    CView::OnLButtonDown(nFlags, point);
}
 
void CMFCApplication2View::OnRButtonDown(UINT nFlags, CPoint point)
{
    ::ClipCursor(NULL); // 해제
    CView::OnRButtonDown(nFlags, point);
}
cs

위 코드는 마우스 포인터를 위치에 따라 바꿀 수 있게 해준다.
마우스 커서가 사각형 안에 있으면 사용자 정의 커서로 바꾸고 밖이면 시스템커서로 바꿔준다.

::ClipCursor(const RECT* lpRect); 커서가 움직일 수 있는 범위를 lpRect 안으로 제한한다.

참고>
마우스커서 모양을 바꾸려면 OnSetCursor(), OnLButtonDown(), OnRButtonDown() 을 구현해야 한다.

 

아래는 표를 그리고 제목줄에서 드래그로 컬럼 폭 조절할때 마우스 포인터 모양을 바꾸는 코드 이다.
자세한 전체 코드 20221001 (비공개) :   https://petra.tistory.com/1731

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class CDataListWnd : public CWnd
{
    ...
private:
    BOOL m_bMouseCursor;
    bool m_is_clicked_title;
}
 
 
void CDataListWnd::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
    point.x += m_nHScroll;
    for (int i = 0; i < m_nColumn_count; i++)
    {
        if (m_pTitleRect[i].PtInRect(point))
        {
            // 마우스 이벤트에서 마으스커서를 직접 변경하면 드래그할때 화살표 마웃으 포인터가 보이는 문제가 있어, 
            // WM_SETCURSOR 메시지 처리기에서 마우스 포인터를 로드한다. 20221001            
            m_bMouseCursor = TRUE;
            SetCursor((AfxGetApp()->LoadStandardCursor(IDC_SIZEWE))); // 제목 세로 경계선에 오면 마우스 커서를 바꾸고 싶은데 여기서 로드 해야만 적용된다. 20221001
        }
        else if (false == m_is_clicked_title)
        {
            m_bMouseCursor = FALSE;
        }
    }
    ...
}
 
 
void CDataListWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
    int nItem = point.y / ITEM_HEIGHT; // 제목줄이 0 이므로 m_nVscroll 은 무시한다. 20220927
    if (0 == nItem)
    {
        CRect rect(m_nHScroll, m_nVScroll * ITEM_HEIGHT, m_view_cx * MAX_WIDTH_SIZE, ITEM_HEIGHT);
        ClientToScreen(&rect);
        ::ClipCursor(&rect); // 마우스커서를 캡쳐할 영역을 지정한다. (항목 크기)
 
        int pos = point.x;
        if (pos > m_pnCol_max[m_nCol] - 3 && pos < m_pnCol_max[m_nCol] + 3// 컬럼의 폭 정보를 가진 배열
            m_is_clicked_title = true;
        else
            m_is_clicked_title = false;
 
        return;
    }
    ...
    
    CWnd::OnLButtonDown(nFlags, point);
}
 
void CDataListWnd::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
    ::ClipCursor(NULL);
 
    if (true == m_is_clicked_title)
    {
        m_is_clicked_title = false;
        m_nCol = -1;
    }
    m_bMouseCursor = FALSE;
 
    CWnd::OnLButtonUp(nFlags, point);
}
 
BOOL CDataListWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
    if(TRUE == m_bMouseCursor)
        SetCursor((AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)));
    else
        SetCursor((AfxGetApp()->LoadStandardCursor(IDC_ARROW)));
    return TRUE; // 여기서 반환하지 않으면 마우스 커서 모양이 드래그할때 계속 바뀌는 문제가 생긴다. 20221001
 
    return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
cs