15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


How do you scroll a subset of a CScrollView?

wtflanders@micron.com
Friday, December 13, 1996

Environment: VC++ 4.2b, Win NT 4.0


Greetings,
I'm creating an app that has a CScrollView derived class 
used to draw electrical signals.  It has a "ruler" on the top of the view and
one the left of the view (similar to Visio.)  I want to scroll only a subset of 
the view (reference the diagram below) as follows:

OnVScroll()
  scroll the "contents + y ruler"; do not scroll "x ruler + c" 
OnHScroll()
  scroll the "contents + x ruler"; do not scroll "y ruler + c" 

The corner, "c", never scrolls.
  

 ----------------------------------------
|c |   x ruler                           | 
|--|-------------------------------------|
|  |                                     |
|y |                                     |
|  |                                     |
|r |     contents                        |
|u |                                     |
|l |                                     |
|e |                                     | 
|r |                                     | 
|  |                                     | 
 ----------------------------------------

Here is a snipet of the code which draws the x ruler and the contents (signals.)
The x ruler scrolls off the screen (the undesired effect.)

void CSignalView::OnDraw(CDC* pDC)
{
    CSignalDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    
    // Get the invalidated rectangle of the view, or in the case
    // of printing, the clipping region of the printer dc.
    CRect rectClip;
    CRect rectSignal;
    pDC->GetClipBox(&rectClip);
    pDC->LPtoDP(&rectClip);
    rectClip.InflateRect(1, 1); // avoid rounding to nothing
    
    // Note: CScrollView::OnPaint() will have already adjusted the
    // viewport origin before calling OnDraw(), to reflect the
    // currently scrolled position.

	DrawRuler(pDC, rectClip);

    CTypedPtrList& SignalList = pDoc->m_SignalList;
    POSITION pos = SignalList.GetHeadPosition();
    while (pos != NULL)	
	{
		CSignal* pSignal = SignalList.GetNext(pos);
		rectSignal = pSignal->GetBoundingRect();
		pDC->LPtoDP(&rectSignal);
		rectSignal.InflateRect(1, 1); // avoid rounding to nothing
		if (!rectSignal.IntersectRect(&rectSignal, &rectClip))
			continue;
		pSignal->DrawSignal(pDC);
    }
}


void CSignalView::DrawRuler(CDC* pDC, CRect& clipRect, const int InX/*=100*/)
{
	//Draw Frame...  pDC->FrameRect(...);	  or pDC->FrameRgn()
    CPen penRuler;
    char buffer[256];
    
    if (!penRuler.CreatePen(PS_SOLID, 1, RGB(0,0,200)))	
		return;
    CPen* pOldPen = pDC->SelectObject(&penRuler);

	int yOffset=10;
	int xOffset=25;

	int y=5;
	int x=InX;
	pDC->MoveTo(x,y);

	CPoint bounds=clipRect.BottomRight();
	bounds.x -= 10;

	pDC->LineTo(bounds.x, y);  
	for(x=InX;xPtVisible(x,y))
			x=bounds.x+1;	//end loop
		else
		{
			pDC->MoveTo(x,y);
			pDC->LineTo(x, y+yOffset);
		}
	}

    pDC->SelectObject(pOldPen);
}

I've checked books, MSDN, the MFC-L archive, and tried various CDC and 
CScrollView member functions to try to get this effect.   

Any suggestions would be most appreciated,
Bill Flanders
WTFlanders@Micron.com
  										 

PS-My next approach will be to let the scrolling work as is (x&y rulers scroll 
of page) and redraw the rulers based over the visible portion of the contents 
window coordinates.



aworlow@ns.Sperry-Sun.COM
Monday, December 16, 1996

[Mini-digest: 4 responses]


     Environment: VC++ 4.2b, Win NT 4.0
     
     
     
     
     I have just completed a project in which I faced the same problem.  I 
     found a couple of ways to avoid this problem:
     
     1.) Make the "X ruler" a non-client window in the view class.  The 
     CScrollView always expects to scroll the entire client area.
     
     2.) If making a non-client window is not an option, "borrow" the 
     CSrollView class and create a new scroll view class.  Replace the 
     ScrollWindow() functions to include the window rect to be scrolled, 
     the default is the entire client rect.
     
     I hope this will help!
     
     A. Worlow


        aworlow@sperry-sun.com
        My opinions are my own, and better left that way!?

______________________________ Reply Separator _________________________________
Subject: How do you scroll a subset of a CScrollView?
Author:  mfc-l@NETCOM.COM at Internet-Mail
Date:    12/15/96 8:31 PM


Environment: VC++ 4.2b, Win NT 4.0
     
     
Greetings,
I'm creating an app that has a CScrollView derived class 
used to draw electrical signals.  It has a "ruler" on the top of the view and 
one the left of the view (similar to Visio.)  I want to scroll only a subset of 
the view (reference the diagram below) as follows:
     
OnVScroll()
  scroll the "contents + y ruler"; do not scroll "x ruler + c" 
OnHScroll()
  scroll the "contents + x ruler"; do not scroll "y ruler + c" 
     
The corner, "c", never scrolls.
     
     
 ----------------------------------------
|c |   x ruler                           | 
|--|-------------------------------------| 
|  |                                     | 
|y |                                     | 
|  |                                     | 
|r |     contents                        | 
|u |                                     | 
|l |                                     | 
|e |                                     | 
|r |                                     | 
|  |                                     | 
 ----------------------------------------
     
Here is a snipet of the code which draws the x ruler and the contents (signals.)
The x ruler scrolls off the screen (the undesired effect.)
     
void CSignalView::OnDraw(CDC* pDC)
{
    CSignalDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
     
    // Get the invalidated rectangle of the view, or in the case 
    // of printing, the clipping region of the printer dc.
    CRect rectClip;
    CRect rectSignal;
    pDC->GetClipBox(&rectClip);
    pDC->LPtoDP(&rectClip);
    rectClip.InflateRect(1, 1); // avoid rounding to nothing
     
    // Note: CScrollView::OnPaint() will have already adjusted the 
    // viewport origin before calling OnDraw(), to reflect the
    // currently scrolled position.
     
 DrawRuler(pDC, rectClip);
     
    CTypedPtrList& SignalList = pDoc->m_SignalList; 
    POSITION pos = SignalList.GetHeadPosition();
    while (pos != NULL) 
 {
  CSignal* pSignal = SignalList.GetNext(pos); 
  rectSignal = pSignal->GetBoundingRect(); 
  pDC->LPtoDP(&rectSignal);
  rectSignal.InflateRect(1, 1); // avoid rounding to nothing 
  if (!rectSignal.IntersectRect(&rectSignal, &rectClip))
   continue;
  pSignal->DrawSignal(pDC);
    }
}
     
     
void CSignalView::DrawRuler(CDC* pDC, CRect& clipRect, const int InX/*=100*/) 
{
 //Draw Frame...  pDC->FrameRect(...);   or pDC->FrameRgn()
    CPen penRuler;
    char buffer[256];
     
    if (!penRuler.CreatePen(PS_SOLID, 1, RGB(0,0,200))) 
  return;
    CPen* pOldPen = pDC->SelectObject(&penRuler);
     
 int yOffset=10;
 int xOffset=25;
     
 int y=5;
 int x=InX;
 pDC->MoveTo(x,y);
     
 CPoint bounds=clipRect.BottomRight(); 
 bounds.x -= 10;
     
 pDC->LineTo(bounds.x, y);  
 for(x=InX;xPtVisible(x,y))
   x=bounds.x+1; //end loop
  else
  {
   pDC->MoveTo(x,y);
   pDC->LineTo(x, y+yOffset);
  }
 }
     
    pDC->SelectObject(pOldPen);
}
     
I've checked books, MSDN, the MFC-L archive, and tried various CDC and 
CScrollView member functions to try to get this effect.   
     
Any suggestions would be most appreciated, 
Bill Flanders
WTFlanders@Micron.com
     
     
PS-My next approach will be to let the scrolling work as is (x&y rulers scroll 
of page) and redraw the rulers based over the visible portion of the contents 
window coordinates.

-----From: Lee Thompson 

Hi,

Way back when I did this by using splitter views. I split the window
both ways, set the focus to the "contents" view, and passed along the
appropriate scroll messages to the correct view, such as on horizontal
scroll, I let the contents window scroll and also pass it along to the x
ruler view. It was something like:

///these two scroll routines give fast update for secondary panes - see
timer for it's reason for living
void CAdarprtView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar) 
{
	if(nSBCode == SB_PAGEUP || nSBCode == SB_PAGEDOWN)
		return;		//skip these scroll messages, they dont seem to work right

	KillTimer(m_nTimer);	//so doesn't fire while we are using scroll bars

	CMainFrame* pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
	
	//scroll the pane that sent the message	
	CEditView::OnVScroll(nSBCode, nPos, pScrollBar);
	//scroll other pane in this row
	pFrame->m_wndSplitter.GetPane(1,0)->SendMessage(WM_VSCROLL, nSBCode,
	MAKELONG(nPos, NULL));

	m_nTimer = SetTimer(1,10, NULL);  //re-start it
	ASSERT(m_nTimer != 0);
}

void CAdarprtView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar) 
{
	if(nSBCode == SB_PAGEUP || nSBCode == SB_PAGEDOWN)
		return;		//skip these scroll messages, they dont seem to work right

	KillTimer(m_nTimer);	//so doesn't fire while we are using scroll bars

	CMainFrame* pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
	
	CEditView::OnHScroll(nSBCode, nPos, pScrollBar);
	pFrame->m_wndSplitter.GetPane(0,1)->SendMessage(WM_HSCROLL, nSBCode,
	MAKELONG(nPos, NULL));

	m_nTimer = SetTimer(1,10, NULL);  //re-start it
	ASSERT(m_nTimer != 0);
	
}


/// Timer routine is neccesary to scroll secondary panes when main pane
is scrolled by using
//  arrow keys to move the caret
void CAdarprtView::OnTimer(UINT nIDEvent) 
{
	CMainFrame* pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
	int VScrollpos =
pFrame->m_wndSplitter.GetPane(1,1)->GetScrollPos(SB_VERT); 
	pFrame->m_wndSplitter.GetPane(1,0)->SendMessage(WM_VSCROLL,
SB_THUMBPOSITION,
	MAKELONG(VScrollpos, NULL));
	
	int HScrollpos =
pFrame->m_wndSplitter.GetPane(1,1)->GetScrollPos(SB_HORZ); 
	pFrame->m_wndSplitter.GetPane(0,1)->SendMessage(WM_HSCROLL,
SB_THUMBPOSITION,
	MAKELONG(HScrollpos, NULL));
	
	CEditView::OnTimer(nIDEvent);
}


Like I said this is old 16bit stuff, and looks like it could be better,
but maybe it will get you started.

Lee Thompson
-----From: "Daniel Munoz" 

Environment: VC++ 4.2, Win 95, NT 3.51, NT 4.00

Here's a fraction of a program I've wrote that have this 2 rulers
functionnality on a scroll view (the world is so small... :-) )

You have to derive your own CMyScrollView from CScrollView, or to duplicate
the SCrollView code to adapt your work
(my sample duplicate the code and derivate directly from CView, because my
CScrollView32 class do many other things 
(like breaking the 16 bits size limit, forcing scrollbars all the time,
handle rulers, add a new MM_TEXT with inverted Y axes...etc )

void CScrollView32::ScrollWindow (int dx, int dy)	//base class is CView
{
	CRect scr;
	GetClientRect(&scr);
	CRect hor=GetRectNoScrollHor ();	//the horizontal rect that must NOT
scroll
	CRect ver=GetRectNoScrollVer ();	//the vertical rect that must NOT scroll
	
	if ( hor.IsRectEmpty () && ver.IsRectEmpty () )
		CView::ScrollWindow ( dx, dy, scr ,scr);
	else if ( !hor.IsRectEmpty () && !ver.IsRectEmpty () )
	{
		CRect UpLeft (scr.left, scr.top, ver.left, hor.top);
		CRect UpRight (ver.right, scr.top, scr.right, hor.top);
		CRect DownLeft (scr.left, hor.bottom, ver.left, scr.bottom);
		CRect DownRight (ver.right, hor.bottom, scr.right, scr.bottom);

		//scroll order optimisation (Retru's rules) to have a nice viewing
		if (dx)		//horizontal scroll
		{
			if (!UpLeft.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, UpLeft,
UpLeft);
			if (!DownLeft.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, DownLeft,
DownLeft);
			if (!UpRight.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, UpRight,
UpRight);
			if (!DownRight.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, DownRight,
DownRight);
		}
		else	//vertical scroll
		{
			if (!UpLeft.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, UpLeft,
UpLeft);
			if (!UpRight.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, UpRight,
UpRight);
			if (!DownLeft.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, DownLeft,
DownLeft);
			if (!DownRight.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, DownRight,
DownRight);
		}
	}
	else if ( !hor.IsRectEmpty () && ver.IsRectEmpty () )
	{
		CRect Up (scr.left, scr.top, scr.right, hor.top);
		CRect Down (scr.left, hor.bottom, scr.right, scr.bottom);
		if (!Up.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, Up, Up);
		if (!Down.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, Down, Down);
	}
	else if ( hor.IsRectEmpty () && !ver.IsRectEmpty () )
	{
		CRect Left (scr.left, scr.top, ver.left, scr.bottom);
		CRect Right (ver.right, scr.top, scr.right, scr.bottom);
		if (!Left.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, Left, Left);
		if (!Right.IsRectEmpty ()) CView::ScrollWindow ( dx, dy, Right, Right);
	}
	else
	{
		TRACE ("Error ! CScrollView32::ScrollWindow (%d,%d)\n",dx,dy);
		ASSERT (FALSE);
	}
}



Daniel Munoz
dmunoz@socabim.fr

-----From: Tony DiBlasio 


------ =_NextPart_000_01BBEC14.F766C870
Content-Type: text/plain; charset="us-ascii"




| Вернуться в корень Архива |