Application/Windows

[MFC] Dialog에 스크롤 막대 적용하는 방법

elisom 2023. 8. 24. (Last updated:

 

 

높이가 긴 다이얼로그를 특정 높이로 지정하고,

스크롤바를 사용하여 모든 내용을 볼 수 있도록 구현하고자 한다.

 

 

Add Style on Dialog

리소스 뷰를 사용하여 내용이 긴 다이얼로그를 생성한 후 

속성에서 모양/세로 스크롤 막대True 하여 다이얼로그에 세로 스크롤 막대를 생성합니다.

TestApp.rc 파일을 보면, 해당 다이얼로그의 STYLE으로 WS_VSCROLL가 추가되어 있는 것을 확인할 수 있습니다.

 

이렇게 세로 스크롤 막대를 True로 지정한다고 해서

곧바로 우리가 원하는 대로 스크롤바가 동작하지 않습니다.🥲

 

 

Add Method for Message

클래스 마법사 또는 속성 창에서 WM_VSCROLL 메시지에 대한 함수를 생성합니다.

(함수 기본 이름: OnVScroll)

void TestDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

    CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

기본적으로 생성된 OnVScroll() 함수는 위와 같습니다.

 

 

OnInitDialog()

OnVScroll()을 작성하기 전에, OnInitDialog() 함수에서 스크롤에 대한 초기화를 합니다.

BOOL TestDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // TODO:  여기에 추가 초기화 작업을 추가합니다.
    GetWindowRect(m_rect);
    this->SetWindowPos(NULL, NULL, NULL, m_rect.Width(), m_nWndHeight, SWP_NOMOVE);

    InitVscroll();

    return TRUE;  // return TRUE unless you set the focus to a control
                  // 예외: OCX 속성 페이지는 FALSE를 반환해야 합니다.
}

저는 길게 만들어놓은 다이얼로그에서 높이를 특정한 값으로 고정하기 위해 SetWindowPos()를 사용했습니다.

고정 높이는 m_nWndHeight으로 미리 선언한 값 500을 사용하고, 너비는 window의 너비를 받아 그대로 사용합니다.

SWP_NOMOVE flag를 추가하여 위치 이동은 하지 않고, 너비와 높이만 조절하도록 했습니다.

 

InitVScroll() 함수를 만들어 SCROLLINFO를 초기화하는 메서드를 구현합니다.

void TestDlg::InitVScroll()
{
    SCROLLINFO si;
    int nScrollMax = m_rect.Height() - 1;
    int nPageSize = m_nWndHeight;
    m_nScrollPos = 0;

    si.cbSize = sizeof(SCROLLINFO);
    si.fMask = SIF_ALL;

    GetScrollInfo(SB_VERT, &si);

    si.nMin = 0;
    si.nMax = nScrollMax;
    si.nPage = nPageSize;
    si.nPos = m_nScrollPos;
    SetScrollInfo(SB_VERT, &si, TRUE);
}

한 페이지의 크기는 보여지는 화면 높이로 하고, 나머지는 아래 문서를 참고하여 초기화합니다.

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/ns-winuser-scrollinfo

 

SCROLLINFO (winuser.h) - Win32 apps

The SCROLLINFO structure contains scroll bar parameters to be set by the SetScrollInfo function (or SBM_SETSCROLLINFO message), or retrieved by the GetScrollInfo function (or SBM_GETSCROLLINFO message).

learn.microsoft.com

 

 

OnVScroll()

OnVScroll()의 세 매개변수는

nSBCode: 스크롤 요청 방법

nPos: 스크롤 현재 위치

pScrollBar: 스크롤 바 컨트롤에 대한 포인터

를 나타냅니다.

 

위의 세 매개변수 외에, 두 변수를 사용합니다.

nNextPos: 스크롤 후의 위치

nDelta: 스크롤 변화량

 

void TestDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

    int nNextPos = 0;
    int nDelta = 0;
    SCROLLINFO si = { 0, };

    si.cbSize = sizeof(SCROLLINFO);
    si.fMask = SIF_ALL;
    GetScrollInfo(SB_VERT, &si);

    switch (nSBCode) {
    case SB_THUMBTRACK:
        nNextPos = nPos;
        nDelta = -(nNextPos - si.nPos);
        break;
    case SB_LINEUP:
        nNextPos = si.nPos - 20;
        nDelta = 20;
        if (nNextPos < 0) {
            nNextPos = 0;
            nDelta = si.nPos;
        }
        break;
    case SB_PAGEUP:
        nNextPos = si.nPos - si.nPage;
        nDelta = si.nPage;
        if (nNextPos < 0) {
            nNextPos = 0;
            nDelta = si.nPos;
        }
        break;
    case SB_LINEDOWN:
        nNextPos = si.nPos + 20;
        nDelta = -20;
        if (nNextPos + si.nPage >= si.nMax) {
            if (si.nPos + si.nPage >= si.nMax) {
                nDelta = 0;
                nNextPos = si.nPos;
            }
            else {
                nDelta = (20 - ((nNextPos + si.nPage) - si.nMax));
                nNextPos = si.nMax - si.nPage;
                nDelta = -nDelta;
            }
        }
        break;
    case SB_PAGEDOWN:
        nNextPos = si.nPos + si.nPage;
        nDelta = si.nPage;
        if (nNextPos + si.nPage >= si.nMax) {
            nNextPos = si.nMax - si.nPage;
            nDelta = nNextPos - si.nPos;
        }
        nDelta = -nDelta;
        break;
    default:
        return;
    }

    m_nScrollPos = nNextPos;
    SetScrollPos(SB_VERT, nNextPos, TRUE);
    ScrollWindow(0, nDelta);

    CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

nSBCode에 따라 nNextPosnDelta 값을 계산한 후

SetScrollPos(), ScrollWindow() 하여 스크롤 바와 화면을 이동시킵니다.

 

 

Ref.

이 글은 Vertical scrolling만 다루고 있지만, 아래의 글은 Horizontal scrolling도 다루고 있습니다.

OnSize()에 대한 구현도 포함되어 있으니 참고하시면 좋을 것 같습니다🤓

 

https://nanze.tistory.com/entry/MFC-다이얼로그Dialog-스크롤Scroll-적용

 

MFC 다이얼로그(Dialog) 스크롤(Scroll) 적용

MFC에서 다이얼로그에 스크롤을 적용하기 위한 코드를 보도록 하자. 우선 리소스에디터에서 해당 다이얼로그의 속성 중 Border 를 Resizing 으로 수정해 놓아야 한다. 그 이후 필요한 것은 크기 변동

nanze.tistory.com

 

 

 

'Application > Windows' 카테고리의 다른 글

[WPF] UserControl 만들기  (1) 2024.02.23