📄 visdrawscrollview.cpp
字号:
// VisDrawScrollView.cpp : 实现文件
//
#include "stdafx.h"
#include "VisDraw.h"
//#include "VisDrawScrollView.h"
#include ".\visdrawscrollview.h"
// CVisDrawScrollView
IMPLEMENT_DYNCREATE(CVisDrawScrollView, CScrollView)
CVisDrawScrollView::CVisDrawScrollView()
{
m_bCenter = TRUE;
m_bExtendX = FALSE;
m_bExtendY = FALSE;
m_Delta = 0;
m_Center = CPoint(0, 0);
m_Offset = CPoint(0, 0);
m_Ratio = CSize(1, 1);
}
CVisDrawScrollView::~CVisDrawScrollView()
{
}
BEGIN_MESSAGE_MAP(CVisDrawScrollView, CScrollView)
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
// CVisDrawScrollView 绘图
void CVisDrawScrollView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: 在此添加绘制代码
}
// CVisDrawScrollView 诊断
#ifdef _DEBUG
void CVisDrawScrollView::AssertValid() const
{
CScrollView::AssertValid();
}
void CVisDrawScrollView::Dump(CDumpContext& dc) const
{
CScrollView::Dump(dc);
}
#endif //_DEBUG
// CVisDrawScrollView 消息处理程序
CSize CVisDrawScrollView::GetTotalSize() const
{
// return the true total size (scroll view + offset)
return m_TotalSize;
}
void CVisDrawScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage, const SIZE& sizeLine)
{
long cx, cy;
// save total size
ASSERT(sizeTotal.cx > 0 && sizeTotal.cy > 0);
CSize TotalSize = sizeTotal;
// compute document size in logical unit
cx = sizeTotal.cx;
cy = sizeTotal.cy;
// scroll size can't be greater than 32768
if (sizeTotal.cx > 32768) sizeTotal.cx = 32768;
if (sizeTotal.cy > 32768) sizeTotal.cy = 32768;
// calculate if BigScrollSize greater than ScrollSize
cx -= sizeTotal.cx; m_bExtendX = (cx != 0);
cy -= sizeTotal.cy; m_bExtendY = (cy != 0);
// if first time, init client center and offset
if (m_nMapMode == MM_NONE)
{
ASSERT(nMapMode > 0);
int y = sizeTotal.cy / 2;
if (nMapMode != MM_TEXT) y = -y;
m_Center = CPoint(sizeTotal.cx / 2, y);
m_Offset = CPoint(cx / 2, cy / 2);
m_Ratio = TotalSize;
}
else SaveClientCenter();
// to correct scroll position between DP and LP
m_Delta = 0;
if (nMapMode != MM_TEXT)
{
ASSERT(nMapMode > 0);
CPoint point(1, 1);
CWindowDC dc(NULL);
dc.SetMapMode(nMapMode);
dc.DPtoLP(&point);
m_Delta = point.x;
}
SetRedraw(FALSE);
CScrollView::SetScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);
m_TotalSize = TotalSize;
RestoreClientCenter();
SetRedraw(TRUE);
Invalidate(TRUE);
}
//把设备坐标转化为逻辑坐标
void CVisDrawScrollView::ClientToDoc(CPoint& Point)
{
CClientDC dc(this);
OnPrepareDC(&dc, NULL);
dc.DPtoLP(&Point);
Point += m_Offset;
}
//把设备坐标转化为逻辑坐标
void CVisDrawScrollView::ClientToDocDraw(CPoint& Point)
{
CClientDC dc(this);
OnPrepareDC(&dc, NULL);
dc.DPtoLP(&Point);
}
//把设备矩形转化为逻辑矩形
void CVisDrawScrollView::ClientToDoc(CRect& rect)
{
CPoint point = (m_nMapMode != MM_NONE) ? GetDeviceScrollPosition(): CPoint(0, 0);
rect += point;
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(rect);
}
rect += m_Offset;
}
//把设备矩形转化为逻辑矩形
void CVisDrawScrollView::ClientToDocDraw(CRect& rect)
{
CPoint point = (m_nMapMode != MM_NONE) ? GetDeviceScrollPosition(): CPoint(0, 0);
rect += point;
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(rect);
}
}
//把逻辑坐标转化为设备坐标
void CVisDrawScrollView::DocToClient(CPoint& point)
{
CClientDC dc(this);
OnPrepareDC(&dc, NULL);
dc.LPtoDP(&point);
// point -= m_Offset;
}
//把矩形逻辑矩形转化为设备矩形
void CVisDrawScrollView::DocToClient(CRect& rect)
{
CClientDC dc(this);
OnPrepareDC(&dc, NULL);
dc.LPtoDP(rect);
rect.NormalizeRect();
// rect -= m_Offset;
}
CPoint CVisDrawScrollView::GetLogPosition(CPoint Point) const
{
// return the true point position (scroll view + offset)
CPoint point = (m_nMapMode != MM_NONE) ? GetDeviceScrollPosition(): CPoint(0, 0);
Point += point;
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(&Point);
}
Point += m_Offset;
return Point;
}
//把矩形设备坐标转化为逻辑坐标
void CVisDrawScrollView::GetLogPosition(CRect &rect)
{
// return the true point position (scroll view + offset)
CPoint point = (m_nMapMode != MM_NONE) ? GetDeviceScrollPosition(): CPoint(0, 0);
rect += point;
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(rect);
}
rect += m_Offset;
}
CPoint CVisDrawScrollView::GetDeviceScrollPosition() const
{
CPoint pt(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
ASSERT(pt.x >= 0 && pt.y >= 0);
if (m_bCenter)
{
CRect rect;
GetClientRect(&rect);
// if client area is larger than total device size,
// the scroll positions are overridden to place origin such that
// output is centered in the window
// GetDeviceScrollPosition() must reflect this
if (m_totalDev.cx < rect.Width())
pt.x = -((rect.Width() - m_totalDev.cx) / 2);
if (m_totalDev.cy < rect.Height())
pt.y = -((rect.Height() - m_totalDev.cy) / 2);
}
return pt;
}
//获取设备坐标原点
CPoint CVisDrawScrollView::GetDeviceOrg() const
{
CPoint pointOrg = GetDeviceScrollPosition();
if (pointOrg.x > 0) pointOrg.x = 0;
if (pointOrg.y > 0) pointOrg.y = 0;
pointOrg.x = abs(pointOrg.x);
pointOrg.y = abs(pointOrg.y);
return pointOrg;
}
//得到客户区矩形逻辑坐标
void CVisDrawScrollView::GetLogClientRect(CRect *pRect) const
{
// return the true client rectangle (scroll view + offset)
GetClientRect(pRect);
CPoint point = (m_nMapMode != MM_NONE) ? GetDeviceScrollPosition(): CPoint(0, 0);
pRect->OffsetRect(point.x, point.y);
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(pRect);
}
pRect->OffsetRect(m_Offset);
}
CPoint CVisDrawScrollView::GetLogClientCenter() const
{
// return the true client center (scroll view + offset)
CRect rect;
GetLogClientRect(&rect);
return rect.CenterPoint();
}
void CVisDrawScrollView::SaveClientCenter()
{
// save client center and scale factor
m_Center = GetLogClientCenter();
m_Ratio = m_TotalSize;
}
void CVisDrawScrollView::RestoreClientCenter()
{
// update client center with scale and restore center
m_Center.x = MulDiv(m_Center.x, m_TotalSize.cx, m_Ratio.cx);
m_Center.y = MulDiv(m_Center.y, m_TotalSize.cy, m_Ratio.cy);
CenterOnPoint(m_Center);
}
void CVisDrawScrollView::CenterOnPoint(CPoint ptCenter)
{
// save scroll position & offset
CPoint savePosition = CScrollView::GetScrollPosition();
CPoint saveOffset = m_Offset;
CRect rect; GetClientRect(&rect);
CPoint Center = rect.CenterPoint();
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(&Center);
}
// reverse direction
if (m_nMapMode != MM_TEXT)
{
ptCenter.y = -ptCenter.y;
Center.y = -Center.y;
}
CPoint Position(ptCenter.x - Center.x, ptCenter.y - Center.y);
if (m_bExtendX) // BigScrollSize < ScrollSize
{
// window is left over
if (ptCenter.x < Center.x)
{
Position.x = 0;
m_Offset.x = 0;
}
// page is left over
else if (ptCenter.x < 16384)
{
Position.x = (int)(ptCenter.x - Center.x);
m_Offset.x = 0;
}
// window is right over
else if (ptCenter.x + Center.x > m_TotalSize.cx)
{
Position.x = (int)(32768 - 2 * Center.x);
m_Offset.x = m_TotalSize.cx - 32768;
}
// page is right over
else if (ptCenter.x + 16384 > m_TotalSize.cx)
{
Position.x = (int)(32768 - Center.x - m_TotalSize.cx + ptCenter.x);
m_Offset.x = m_TotalSize.cx - 32768;
}
// page is centered
else
{
Position.x = (int)(16384 - Center.x);
m_Offset.x = ptCenter.x - 16384;
}
}
else m_Offset.x = 0;
if (m_bExtendY) // BigScrollSize < ScrollSize
{
// window is top over
if (ptCenter.y < Center.y)
{
Position.y = 0;
m_Offset.y = 0;
}
// page is top over
else if (ptCenter.y < 16384)
{
Position.y = (int)(ptCenter.y - Center.y);
m_Offset.y = 0;
}
// window is bottom over
else if (ptCenter.y + Center.y > m_TotalSize.cy)
{
Position.y = (int)(32768 - 2 * Center.y);
m_Offset.y = m_TotalSize.cy - 32768;
}
// page is bottom over
else if (ptCenter.y + 16384 > m_TotalSize.cy)
{
Position.y = (int)(32768 - Center.y - m_TotalSize.cy + ptCenter.y);
m_Offset.y = m_TotalSize.cy - 32768;
}
// page is centered
else
{
Position.y = (int)(16384 - Center.y);
m_Offset.y = ptCenter.y - 16384;
}
}
else m_Offset.y = 0;
// reverse direction
if (m_nMapMode != MM_TEXT)
{
ptCenter.y = -ptCenter.y;
Position.y = -Position.y;
m_Offset.y = -m_Offset.y;
}
if (Position != savePosition)
{
CScrollView::ScrollToPosition(Position);
}
// if offset change, scroll window
if (saveOffset != m_Offset)
{
CSize sizeScroll(saveOffset.x - m_Offset.x, saveOffset.y - m_Offset.y);
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.LPtoDP(&sizeScroll);
}
ScrollWindow(sizeScroll.cx, -sizeScroll.cy);
}
SaveClientCenter();
}
CPoint CVisDrawScrollView::GetScrollPosition() const
{
// return the true scroll position (scroll view + offset)
CPoint point = CScrollView::GetScrollPosition();
point += m_Offset;
return point;
}
void CVisDrawScrollView::ScrollToPosition(POINT Point)
{
CRect rect;
GetLogClientRect(&rect);
Point.x += rect.Width() / 2;
Point.y += rect.Height() / 2;
// use center on point to scroll to, new offset will be calculated
CenterOnPoint(Point);
}
void CVisDrawScrollView::SetScaleToFitSize(SIZE sizeTotal)
{
// do not use CScrollView::SetScaleToFit();
// this function change the size of the view !
CSize sizeClient, sizeSb;
GetTrueClientSize(sizeClient, sizeSb);
if (m_nMapMode != MM_TEXT)
{
ASSERT(m_nMapMode > 0); // must be set
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
dc.DPtoLP(&sizeClient);
}
if (sizeClient.cy < MulDiv(sizeTotal.cy, sizeClient.cx, sizeTotal.cx))
{
// add 1% to eliminate scroll bars
sizeTotal.cy = MulDiv(sizeTotal.cy, 101, 100);
sizeTotal.cx = MulDiv(sizeTotal.cx, sizeClient.cy, sizeTotal.cy);
sizeTotal.cy = sizeClient.cy;
}
else
{
// add 1% to eliminate scroll bars
sizeTotal.cx = MulDiv(sizeTotal.cx, 101, 100);
sizeTotal.cx = sizeClient.cx;
sizeTotal.cy = MulDiv(sizeTotal.cy, sizeClient.cx, sizeTotal.cx);
}
SetScrollSizes(m_nMapMode, sizeTotal);
}
void CVisDrawScrollView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (m_bExtendY && nSBCode != SB_ENDSCROLL)
{
CPoint ScrollPos = CScrollView::GetScrollPosition();
CRect rect; GetLogClientRect(&rect);
int Height = rect.Height();
// reverse direction
if (m_nMapMode != MM_TEXT)
{
ScrollPos.y = -ScrollPos.y;
Height = -Height;
m_Offset.y = -m_Offset.y;
}
CClientDC dc(this);
dc.SetMapMode(m_nMapMode);
SIZE size;
switch (nSBCode)
{
case SB_LINEUP:
case SB_LINEDOWN:
size = m_lineDev;
break;
case SB_PAGEUP:
case SB_PAGEDOWN:
size = m_pageDev;
break;
default:
size.cx = size.cy = 0;
}
dc.DPtoLP(&size);
// on top
if (ScrollPos.y == 0)
{
m_Offset.y -= size.cy;
if (m_Offset.y < 0)
{
MessageBeep(MB_ICONEXCLAMATION);
m_Offset.y = 0;
}
Invalidate(TRUE);
}
// on bottom
else if (ScrollPos.y >= 32768 - Height - m_Delta)
{
m_Offset.y += size.cy;
if (m_Offset.y > m_TotalSize.cy - 32768)
{
MessageBeep(MB_ICONEXCLAMATION);
m_Offset.y = m_TotalSize.cy - 32768;
}
Invalidate(TRUE);
}
// reverse direction
if (m_nMapMode != MM_TEXT)
m_Offset.y = -m_Offset.y;
}
CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
SaveClientCenter();
}
void CVisDrawScrollView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (m_bExtendX && nSBCode != SB_ENDSCROLL)
{
CPoint ScrollPos = CScrollView::GetScrollPosition();
CRect rect; GetLogClientRect(&rect);
int Width = rect.Width();
CClientDC dc(this);
dc.SetMapMode(m_nMapMode);
SIZE size;
switch (nSBCode)
{
case SB_LINELEFT:
case SB_LINERIGHT:
size = m_lineDev;
break;
case SB_PAGELEFT:
case SB_PAGERIGHT:
size = m_pageDev;
break;
default:
size.cx = size.cy = 0;
}
dc.DPtoLP(&size);
// left side
if (ScrollPos.x == 0)
{
m_Offset.x -= size.cx;
if (m_Offset.x < 0)
{
MessageBeep(MB_ICONEXCLAMATION);
m_Offset.x = 0;
}
Invalidate(TRUE);
}
// right side
else if (ScrollPos.x >= 32768 - Width - m_Delta)
{
m_Offset.x += size.cx;
if (m_Offset.x > m_TotalSize.cx - 32768)
{
MessageBeep(MB_ICONEXCLAMATION);
m_Offset.x = m_TotalSize.cx - 32768;
}
Invalidate(TRUE);
}
}
CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);
SaveClientCenter();
}
void CVisDrawScrollView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
switch(nChar)
{
case VK_LEFT:
SendMessage(WM_HSCROLL,SB_LINEUP);
break;
case VK_RIGHT:
SendMessage(WM_HSCROLL,SB_LINEDOWN);
break;
case VK_UP:
SendMessage(WM_VSCROLL,SB_LINEUP);
break;
case VK_DOWN:
SendMessage(WM_VSCROLL,SB_LINEDOWN);
break;
}
CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CVisDrawScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: 在此添加专用代码和/或调用基类
CScrollView::OnPrepareDC(pDC, pInfo);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -