높이가 긴 다이얼로그를 특정 높이로 지정하고,
스크롤바를 사용하여 모든 내용을 볼 수 있도록 구현하고자 한다.
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
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-적용
'Application > Windows' 카테고리의 다른 글
[WPF] UserControl 만들기 (1) | 2024.02.23 |
---|