Synchronization of scrolling between two list controls






4.88/5 (10 votes)
Dec 26, 2001
2 min read

109875

1204
This simple example shows the synchronization of scrolling of two list controls
Introduction
Developing one of my projects I became interested in the idea of synchronizing of scrolling of two list controls - both lists have always had information that coincides in the first column and differs in others. That is why parallel browsing of lists would be very comfortable.
The Solution
My solution is the following.
- Override the class
CListCtrl
and add three new functions in new classCListCtrlEx
.void CListCtrlEx::RedirectHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // Only for WinNT/2000/XP - the beginning of the code if (nSBCode/256==SB_THUMBTRACK || (nSBCode & 0xFF)==SB_THUMBTRACK) { int iX = ((int)nPos - (int)GetScrollPos(SB_HORZ)); Scroll(CSize(iX, 0)); } // Only for WinNT/2000/XP - the end of the code CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar); } void CListCtrlEx::RedirectVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // Only for WinNT/2000/XP - the beginning of the code if (nSBCode/256==SB_THUMBTRACK || (nSBCode & 0xFF)==SB_THUMBTRACK) { int iY = ((int)nPos - (int)GetScrollPos(SB_VERT)) * m_nItemHeight; Scroll(CSize(0, iY)); } // Only for WinNT/2000/XP - the end of the code CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar); } void CListCtrlEx::RedirectKeyScroll(UINT nChar) { switch (nChar) { case VK_UP: OnVScroll(SB_LINEUP, 0, NULL); break; case VK_DOWN: OnVScroll(SB_LINEDOWN, 0, NULL); break; case VK_LEFT: OnHScroll(SB_LINELEFT, 0, NULL); break; case VK_RIGHT: OnHScroll(SB_LINERIGHT, 0, NULL); break; case VK_HOME: OnHScroll(SB_LEFT, 0, NULL); break; case VK_END: OnHScroll(SB_RIGHT,0,NULL); break; case VK_PRIOR: OnVScroll(SB_PAGEUP, 0, NULL); break; case VK_NEXT: OnVScroll(SB_PAGEDOWN, 0, NULL); break; } }
These functions will initiate operation ofOnHScroll/OnVScroll
handler in another list control.
- Add to the class
CListCtrlEx
three variables.CSynchScrollView* m_pViewPos; // pointer to View aplications
This variable will be used for functions call from View application.int m_nNumCtrl; // number of class copy - number of list control
By means of this variable we will be able to define what list control has got the messageWM_HSCROLL/WM_VSCROLL/WM_KEYDOWN
.int m_nItemHeight; // height of an item
To define an item height we use the following function:int CListCtrlEx::GetItemHeight() { CRect ItemRect; GetSubItemRect(1, 1, LVIR_BOUNDS, ItemRect); return ItemRect.bottom - ItemRect.top; }
- Override in the class
CListCtrlEx OnHScroll/OnVScroll/OnKeyDown
handlers.void CListCtrlEx::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if (m_pViewPos->m_boolCheckSynchro) { CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar); m_pViewPos->HorzSynchro(m_nNumCtrl, nSBCode, nPos, pScrollBar); } else CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar); } void CListCtrlEx::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if (nSBCode/256==SB_THUMBTRACK || (nSBCode & 0xFF)==SB_THUMBTRACK || nSBCode/256==SB_THUMBPOSITION || (nSBCode & 0xFF)==SB_THUMBPOSITION) { SCROLLINFO sinfo; sinfo.cbSize=sizeof(sinfo); sinfo.fMask=SIF_TRACKPOS; ::GetScrollInfo(m_hWnd, SB_VERT, &sinfo); nPos=sinfo.nTrackPos; } if (m_pViewPos->m_boolCheckSynchro) { CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar); m_pViewPos->VertSynchro(m_nNumCtrl, nSBCode, nPos, pScrollBar); } else CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar); } void CListCtrlEx::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (m_pViewPos->m_boolCheckSynchro) m_pViewPos->KeySynchro(m_nNumCtrl, nChar); else CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags); }
Everything is simple for
OnHScroll/OnVScroll
functions: if synchronization is on, than we call synchronizer-function from View application after a standard processing. ForOnKeyDown
function, if synchronization is on, standardWM_KEYDOWN
handler is not used at all - for both list controlsOnHScroll/OnVScroll
functions are performed. - In View application we define three functions, which will initiate synchronization of scrolling of list controls.
Function for horizontal synchronization.
void CSynchScrollView::HorzSynchro(int NumCtrl, int SBCode, int Pos, CScrollBar* pSB) { switch (NumCtrl) { case 1: if (SBCode == SB_THUMBTRACK) { m_ctrlSecondList.RedirectHScroll(SB_THUMBTRACK, Pos, NULL); m_ctrlSecondList.RedirectHScroll(SB_THUMBPOSITION, Pos, NULL); m_ctrlSecondList.RedirectHScroll(SB_ENDSCROLL, 0, NULL); } else m_ctrlSecondList.RedirectHScroll(SBCode, Pos, pSB); break; case 2: if (SBCode == SB_THUMBTRACK) { m_ctrlFirstList.RedirectHScroll(SB_THUMBTRACK, Pos, NULL); m_ctrlFirstList.RedirectHScroll(SB_THUMBPOSITION, Pos, NULL); m_ctrlFirstList.RedirectHScroll(SB_ENDSCROLL, 0, NULL); } else m_ctrlFirstList.RedirectHScroll(SBCode, Pos, pSB); break; } }
Function for vertical synchronization.
void CSynchScrollView::VertSynchro(int NumCtrl, int SBCode, int Pos, CScrollBar* pSB) { switch (NumCtrl) { case 1: if (SBCode == SB_THUMBTRACK) { m_ctrlSecondList.RedirectVScroll(SB_THUMBTRACK, Pos, NULL); m_ctrlSecondList.RedirectVScroll(SB_THUMBPOSITION, Pos, NULL); m_ctrlSecondList.RedirectVScroll(SB_ENDSCROLL, 0, NULL); } else m_ctrlSecondList.RedirectVScroll(SBCode, Pos, pSB); break; case 2: if (SBCode == SB_THUMBTRACK) { m_ctrlFirstList.RedirectVScroll(SB_THUMBTRACK, Pos, NULL); m_ctrlFirstList.RedirectVScroll(SB_THUMBPOSITION, Pos, NULL); m_ctrlFirstList.RedirectVScroll(SB_ENDSCROLL, 0, NULL); } else m_ctrlFirstList.RedirectVScroll(SBCode, Pos, pSB); break; } }
Function for keyboard synchronization.
void CSynchScrollView::KeySynchro(int NumCtrl, UINT nChar) { switch (NumCtrl) { case 1: m_ctrlSecondList.RedirectKeyScroll(nChar); break; case 2: m_ctrlFirstList.RedirectKeyScroll(nChar); break; } }
In these functions the number of list control that received
WM_HSCROLL/WM_VSCROLL/WM_KEYDOWN
message is defined, then operation ofOnHScroll/OnVScroll
handler in another list control will be initiated.
Important note - SB_THUMBTRACK processing
When the scroll box is dragged and the mouse button is pressed and not released, a SB_THUMBTRACK
message is generated with each change of a scroll box position. When the mouse button is released, first the SB_THUMBPOSITION
message will be generated and then - SB_ENDSCROLL
message. Therefore, at each generation of the SB_THUMBTRACK
message sequential processing of the SB_THUMBTRACK - SB_THUMBPOSITION - SB_ENDSCROLL
messages in appropriate handlers of opposite list controls should be initiated.
Such design correctly works under Win95/98/Me, but does not work under WinNT/2000 and, probably, XP - I have no opportunity to check it up. I don't know how to explain it. May be the reason lies in some peculiarities of realization of some Win32 API functions for different versions of Windows.
The solution of this problem was offered by Jonathan Liu and I am truly grateful to him. While SB_THUMBTRACK
in the RedirectHScroll/RedirectVScroll
functions Scroll (CSize (X, Y))
is called for direct scrolling of contents of the list controls. I repeat one more time: there is no need in it if Win95/98/Me is used.
Look for details of realization on enclosed demo project. I believe that this solution will be useful for somebody.