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"
| Вернуться в корень Архива
|