• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1177
  • Last Modified:

How to synchronize Scrollbars in more then one child windows in MFC MDI applications?

Hai Friends,
       hope everybody are enjoying the life.

Friends, I got a problem, please help me out.

 I'm coding in VC++, and using MDI application.
Problem is,
If in one child window if I drag a Scroll bar, then simulataneously the scroll bar in other child window also has to move!!!!

Please help me out as early as possible.

Thanks a lot...

Have a nice day!

0
madanponna
Asked:
madanponna
  • 10
  • 8
2 Solutions
 
AlexFMCommented:
This is a way to create MFC MDI application with CScrollView class, which scrolls all it's views synchronously. If number of child views are opened, scrolling of one view scrolls by the same way all others.

1) Create MFC MDI application (I called it Test). On the last step of MFC Application Wizard select CScrollView class instead of CView.
2) Add WM_VSCROLL and WM_HSCROLL message handlers to CTEstView classes and fill them by the following way:

void CTestView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    AfxGetMainWnd()->PostMessage(WM_APP + 1, (WPARAM)this, 0);
   
    CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CTestView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    AfxGetMainWnd()->PostMessage(WM_APP + 1, (WPARAM)this, 0);
   
    CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);
}

3) Open MainFrm.h file and add this line to message map:

    LRESULT OnMessageScroll(WPARAM wParam, LPARAM lParam);     // add this line
    DECLARE_MESSAGE_MAP()                                                          // before this line

4) Open MainFrm.cpp file and add this include line:

#include <afxcoll.h>

5) Add the following code to the beginning of MainFrm.cpp file (before CMainFrame class functions):

// CDocEnumerator — Enumerates all the documents in an MFC application.
// To use:
//
//    CDocEnumerator it;
//    CDocument* pdoc;
//    while ((pdoc=it.Next())!=NULL) {
//       // do something
//    }
//
// Source: http://msdn.microsoft.com/msdnmag/issues/04/05/CQA/
// Paul DiLascia
// From the May 2004 issue of MSDN Magazine.
//
class CDocEnumerator {
private:
    CPtrArray m_doclist; // array of all docs
    int m_iPos;          // current position in array
public:
    CDocEnumerator();
    CDocument* Next();
    void Reset() { m_iPos=-1; }
};


//
CDocEnumerator::CDocEnumerator() {
    CWinApp* pApp = AfxGetApp();
    POSITION pos = pApp->GetFirstDocTemplatePosition();
    while (pos!=NULL) {
        CDocTemplate* pDocTemplate = pApp->GetNextDocTemplate(pos);
        POSITION pos2 = pDocTemplate->GetFirstDocPosition();
        while (pos2!=NULL) {
            m_doclist.Add(pDocTemplate->GetNextDoc(pos2));
        }
    }
    Reset();
}

//////////////////
// Fetch next document.
//
CDocument* CDocEnumerator::Next() {
    if (++m_iPos < m_doclist.GetSize()) {
        return (CDocument*)m_doclist[m_iPos];
    }
    return NULL;
}

6) Add this line to CMainFrame message map, MainFrm.cpp file:

    ON_MESSAGE(WM_APP + 1, OnMessageScroll)          // add this line
END_MESSAGE_MAP()                                                 // before this line

7) Add the following code to MainFrm.cpp file:

LRESULT CMainFrame::OnMessageScroll(WPARAM wParam, LPARAM lParam)
{
    CScrollView* pSourceView = (CScrollView*)wParam;
    CDocEnumerator it;
    CDocument* pdoc;

    while ((pdoc=it.Next())!=NULL)
    {
        POSITION pos = pdoc->GetFirstViewPosition();
       
        CScrollView* pView = (CScrollView*)pdoc->GetNextView(pos);
       
        if ( pView != pSourceView )
        {
            CPoint pt = pSourceView->GetScrollPosition();
            pView->ScrollToPosition(pt);
        }
    }
   
    return 0;
}
0
 
madanponnaAuthor Commented:
Hai Alex,
      I'm very very glad to see your answer, thanks a lot.

But Alex, I'm extreamly sorry, as I did not explained my problem clearly.
But your answer is perfectly correct to my question.

Actully my problem is,  as I already said , I'm using MDI application.

And as you wrote in your answer that to inherit from CScrollView, but as per the requirement I inherited from CView class.

what i'm doing is, i'm splitting the child window into TWO panes in CChildFrm.cpp in OnCreateClient() function using CSplitterWnd object.

First Pane(0,0) is a class derived from CListView. And Second Pane(0,1) also derived from CListView.

I created a check box on the MainFrame, so that when I check it, Scrollbar synchronize should occur.

Suppose assume that there are more than one child window.
After checking the check box for scrollbar synchronization,
****whenever I drag a scrollbar in Pane(0,0) in one child window , then Pane(0,0) of other Child window also has to be dragged.

****Similarly whenever I drag a scrollbar in Pane(0,1) in one window , then Pane(0,1) of other Child window also has to be dragged.

Dear Alex, please solve this problem!!!!!!

Thanks a lot for your previous answer.

Waiting.....




0
 
AndyAinscowFreelance programmer / ConsultantCommented:
From the description of a CView
A view handles scroll-bar messages with the CWnd::OnHScroll and CWnd::OnVScroll member functions
Alex has suggested you override those functions.  

What he did was provide a sample of code not specific to your question BUT one that should function as you require.  Ignore the CScrollView base class and try it with your CListView based class.
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
madanponnaAuthor Commented:
Thanks Andy!!!!

I changed it to CListView, It is working!!!!!!!

But when I  scroll the pane(0,0) in one of the child window, all other scrollbars of pane(0,0) are scrolled but LIST ITEMS are NOT repainting!!!!

I mean the data in other  panes(0,0) are not repainted and even the List Control HEADER is moving !!!!!!
But this is not happening with the pane(0,0) in which i'm dragging the scrollbar!!!

Please tell me how to solve this problem!!! I used Invalidate() but no use!!!

One more doubt is , in the below code which Alex sent for my question ,
/////////////////////////////////////////////////////////////////////////////////////
7) Add the following code to MainFrm.cpp file:
LRESULT CMainFrame::OnMessageScroll(WPARAM wParam, LPARAM lParam)
{
    CScrollView* pSourceView = (CScrollView*)wParam;
    CDocEnumerator it;
    CDocument* pdoc;

    while ((pdoc=it.Next())!=NULL)
    {
        POSITION pos = pdoc->GetFirstViewPosition();
       
        CScrollView* pView = (CScrollView*)pdoc->GetNextView(pos);
       
        if ( pView != pSourceView )
        {
            CPoint pt = pSourceView->GetScrollPosition();
            pView->ScrollToPosition(pt);
        }
    }
   
    return 0;
}
/////////////////////////////////////////////////////////////////////////


In place of "CScrollView" what I have to use? at present scroll bars are moving with the same above code.

But is it correct?

Because , the left pane(0,0) , say class name CLeftPane ,is derived from CListView.
And the right pane(0,1) , say class name CRightPane , is also derived from CListView.

Now in place of "CScrollView", what I have to use? still "CScrollView" is ok?

________________________

Also please see my other question at :
           http://www.experts-exchange.com/Programming/Programming_Languages/Q_21131575.html

Thanks!!!!


Waiting....






0
 
AndyAinscowFreelance programmer / ConsultantCommented:
If it is based on CListView try replacing CScrollView with CListView.
Does that sort it out?
0
 
madanponnaAuthor Commented:
Hai,
  I pasted CListView in place of CScrollView but I get error as below:

error C2039: 'GetScrollPosition' : is not a member of 'CListView'

????
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
OK.  Get a pointer to the CListView and then get the underlying list control

pListView->GetListCtrl().GetScrollPosition()

I think the above line is what you would require.
0
 
madanponnaAuthor Commented:
But Andy, CListView does not have GetScrollPosition() function but it has, GetScrollPos(int nBar), this function returns postion of the scrollbar. I dont find use of GetScrollPos()!!!

What to do now? and more over how to :

/////////////////////////////
But when I  scroll the pane(0,0) in one of the child window, all other scrollbars of pane(0,0) are scrolled but LIST ITEMS are NOT repainting!!!!

I mean the data in other  panes(0,0) are not repainted and even the List Control HEADER is moving !!!!!!
But this is not happening with the pane(0,0) in which i'm dragging the scrollbar!!!

Please tell me how to solve this problem!!! I used Invalidate() but no use!!!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Waiting...
And thanks a lot for quick responses!
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
GetScrollPos(SB_HORZ) or SB_VERT

To repaint after you have scrolled you can use Invalidate() then  UpdateWindow().

Could you zip and e-mail your project to me, I would have a quick look tonight.  info@ainscow.ch
0
 
madanponnaAuthor Commented:
Andy, actually i'm in office now, and I cant send code due to security reasons.

I try with you tips.
But really i'm very much confused!!!!
0
 
madanponnaAuthor Commented:
I did as  you told :

LRESULT CMainFrame::OnMessageScroll(WPARAM wParam, LPARAM lParam)
{
    CScrollView* pSourceView = (CScrollView*)wParam;
    CDocEnumerator it;
    CDocument* pdoc;

    while ((pdoc=it.Next())!=NULL)
    {
        POSITION pos = pdoc->GetFirstViewPosition();
       
        CScrollView* pView = (CScrollView*)pdoc->GetNextView(pos);
       
        if ( pView != pSourceView )
        {
            CPoint pt = pSourceView->GetScrollPosition();
            pView->ScrollToPosition(pt);
->           Invalidate();
->          UpdateWindow();
        }
    }
   
    return 0;
}

Arrows indicate where I'm calling Invalidate and UpdateWindow functions.

But no use !!!!!

Same problem, unable to repaint after scrolling !!!!!

0
 
AndyAinscowFreelance programmer / ConsultantCommented:
No no no, Don't scroll the view itself, scroll the list control that is in the view.
Also you have a CListView -DO NOT CAST IT TO CScrollView, cast it to a CListView and use GetListCtrl() to get the underlying list control.  It is that that you want to scroll the contents of.
 
0
 
madanponnaAuthor Commented:
Andy, in MDI Applications , we wont find Scroll bars, only to the child windows scroll bars will be there, am I right?

And i'm scrolling only the List view's scroll bar.
Andy , here in India, it is night 10pm. I'm leaving now. I catch you tommarrow.

But a milliion  thanks  for your continous replies!!!!!

Waiting for the right answer!!!!!
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
in MDI Applications , we wont find Scroll bars, only to the child windows scroll bars will be there, am I right?

Not really - any window COULD have a scrollbar, just does it make sense for it to have one?



And i'm scrolling only the List view's scroll bar

The code you posted you are casting to a CScrollView, not to a CListView AND you need to get the scrollbar of the CListCtrl which is the functional bit inside the CListView.  Just scrolling the view itself should scroll the control (header moving), not the contents of the list.
0
 
madanponnaAuthor Commented:
Hai Andy,
             I'm doing as you said, but once I cast CScrollView to CListView,
then I cant use GetScrollPostion() function.
But I can use GetScrollPos(int nBar) function, this function return back scroll position,
But  problem is, to which function I have to pass the scroll position which I got from GetScrollPos() function???

Waiting....
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
You want to scroll the ListControl.  So you need a pointerto the list control you want to use SetScrollPos with.
0
 
madanponnaAuthor Commented:
Andy,   I did as you said, as below:  

while ((pdoc=it.Next())!=NULL)
{
        POSITION pos = pdoc->GetFirstViewPosition();
       
        CListCtrl* pView = (CListCtrl*)pdoc->GetNextView(pos);
       
        if ( pView != pSourceView )
        {
            int pScrollPos = pSourceView->GetScrollPos(SB_VERT);
            pView->SetScrollPos(SB_VERT,pScrollPos,TRUE);

        }
}

but when I drag the vertical scroll bar, only in one view that is in which i'm dragging the scrollbar , all the  columns are moving. but in remaining views only vertical scrollbar is moving , columns data is not moving!!!

Waiting...
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Do you invalidate the view after the SetScrollPos ?  (We are getting closer - the scroll bar does show an effect ! )
0
 
madanponnaAuthor Commented:
Thanks to all for helping to solve my problem.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 10
  • 8
Tackle projects and never again get stuck behind a technical roadblock.
Join Now