MFC CScrollView中的设备坐标和逻辑坐标转换

CView派生类的说明
  • CEdit View 实现像便签多行正文编辑器的视图
  • CFormView 使用对话框控件模板资源来定义用户应用程序接口的滚动视图
  • CListView 支持重点在列表控件的文档/视图结构的视图
  • CRecordView 显示对话框控件中的数据库记录的视图
  • CRichEditView 支持重点在金莲能编辑控件的文档/视图结构的视图
  • CScrollView 提供支持自动化滚动的视图
  • CTreeView 支持重点在树控件的文档/视力结构的视图

这些增强的视类,都可以作为应用程序视图类的基类。

例如用CScrollView作为应用程序视图类的基类,那么在Class View窗口中就会看到,应用程序视图类中含有一个成员函数
OnInitialUpdate.它是一个虚函数.它在 生成视图对象且与文档结合时,被程序框架调用一次,因此这是初始化滚动条参数的地方.
其原型为:
void SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault)
(
    int nMapMode, //映射模式,一般为MM_TEXT 
    SIZE sizeTotal, //文档尺寸
    const SIZE& sizePage=sizeDefault, //每滚动一页的尺寸
    const SIZE& sizeLine=sizeDefault
); //每滚动一行的尺寸
在6_3的基础上
void CRVView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
	// TODO: remove this code when final selection model code is written
	m_bLeftDown=0;
	m_pSelection = NULL;    // initialize selection
	m_bActive=1;
	CSize sizeTotal;
	// TODO: calculate the total size of this view
	CSize size = GetDocument()->GetSize();
	CClientDC dc(NULL);
	size.cx = MulDiv(size.cx, dc.GetDeviceCaps(LOGPIXELSX), 100);
	size.cy = MulDiv(size.cy, dc.GetDeviceCaps(LOGPIXELSY), 100);
	int a=size.cx;
	int b=size.cy;
	SetScrollSizes(MM_TEXT, size);//size设置滚动式图总的尺寸
	m_View=this;
}
如果按上面的方法编写处理滚动条的代码,还是会出现一些问题的.因为使用滚动条后,窗口已经向右发生移动,从而 使文档的坐标原点与视图的原点实际已不再重合了.但是由于 视图类不能对此变化进行自动修正.

解决方法:在绘图时就需要把 视图的坐标转换为 文档的坐标,而在 显示文档数据时则需 把文档的坐标再转换为 视类的坐标,可以用DC类的成员函数 DPtoLPLPtoDP
void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;
void DPtoLP( LPRECT lpRect ) const;
void DPtoLP( LPSIZE lpSize ) const;
//和
void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;
void LPtoDP( LPRECT lpRect ) const;
void LPtoDP( LPSIZE lpSize ) const;
其中函数DPtoLP能把 设备坐标(视图坐标)转换为 逻辑坐标(文档坐标)
而LPtoDP则相反
把6_4的OnLButtoDown()和OnUpdate()的代码做如下修改. 
void CMy6_4View::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

    CClientDC dc(this); //获得视图的DC
    OnPrepareDC(& dc); //这是一个和坐标映射相关的函数
    dc.DPtoLP(& point); //在绘图之前把鼠标位置传票转换为逻辑坐标.
    pObj->DoOut(point);    //绘图函数
};

windows对 所有的消息 (如WM_SIZE,WM_MOUSEMOVE,WM_LBUTTONDOWNWM_LBUTTONUP,所有的非GDI函数和少数GDI函数(如GetDeviceCaps函数)和 SetViewportExtExSetViewportOrgEx GetMessageGetCursorPosGetWindowRectWindowFromPointSetBrushOrg、InvalidateRect 永远使用 设备坐标 。对大部分的GDI函数(如 Ellipse,Rectangle等 )、 SetWindowExtEx 使用 逻辑坐标
void CRVView::InvalObj(CDrawObj *pObj)
{
	CRect rect = pObj->m_position;
	DocToClient(rect);
	if (m_bActive && IsSelected(pObj))
	{
		rect.left -= 4;
		rect.top -= 5;
		rect.right += 5;
		rect.bottom += 4;
	}
	rect.InflateRect(1, 1); // handles CDrawOleObj objects
	InvalidateRect(rect, FALSE);
}

你可能感兴趣的:(MFC CScrollView中的设备坐标和逻辑坐标转换)