
높이가 긴 다이얼로그를 특정 높이로 지정하고,
스크롤바를 사용하여 모든 내용을 볼 수 있도록 구현하고자 한다.
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에 따라 nNextPos와 nDelta 값을 계산한 후
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