估计很多人都会遇到这么一个问题,平时我们用单文档/视图结构时,很容易就在客户区画个图,画根线什么的,然而,要在对话框的某个控件中画这些东西,刚一上来,还真有点搞吧。
下面,我就把在对话框中对某个控件画图的程序先列出来,然后再看看微软的一些搞的地方。
初始化:
m_IsDrawing=false;
CWnd*pCanvas=GetDlgItem(IDC_CANVAS);
pCanvas->GetWindowRect(&m_Canvas);
ScreenToClient(&m_Canvas);
void CPaintORamaDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
/////////////////////////////////////////
//Add code
//---------------------------------------
if(m_Canvas.PtInRect(point))
{
m_IsDrawing=true;
m_LineStart=point;
SetCapture();
}
}
void CPaintORamaDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//////////////////////////////////////////////
//Add Code
//------------------------------------------
m_IsDrawing=false;
ReleaseCapture();
}
void CPaintORamaDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
////////////////////////////////////////
//Add Code
//-----------------------------------------------
if(m_Canvas.PtInRect(point))
{
if(m_IsDrawing && (nFlags&MK_LBUTTON))
{
CClientDC dc(this);
dc.MoveTo(m_LineStart);
dc.LineTo(point);
m_LineStart=point;
}
}
}
首先,说明一点的是,通过鼠标单击或者移动传进来的CPoint是一个客户坐标,在文档/视图程序中,也就是客户区,用GetClientRect可以获得该区域。而在对话框中,CPoint还是表示客户区,只不过这个时候这个客户区就是整个的对话框自己,整个对话框就是客户区。必须通过this->GetClientRect来获取,它的top和left都是0。right和botton分别是该对话框的宽与高。
这时,假如我们想在对话框中的某个控件画图,按照我们的想法,获取该控件的窗口以及它的DC,然后我们就可以画图了,实际不是这样的,中间还需要一次转换,请看下面代码:
1 CRect lpRect;2 CStatic *m_static = (CStatic*)GetDlgItem(IDC_STATIC1);
3 m_static->GetClientRect(&lpRect);
4 CDC *pDC = m_static->GetDC();
5 pDC->MoveTo(CPoint point);
6 pDC->Ellipse(...);
等等
上面的这些操作有以下问题,
1. 第三句中,通过GetClientRect来获取客户区,我们知道该函数是获取窗体的客户区,那么上面第三句就是获得该控件的客户区,它的top和left都为0,right和botton是宽和高。然而,前面我们说过,通过鼠标传入的CPoint是一个以整个对话框为客户区的客户区坐标,即它是以整个对话框的左上顶角点作为坐标原点计算的。所以这两者根本无法联系在一起,所以也就不能在该控件上画出这个点了。
这时,我们想起了另一个函数, GetWindowRect(),可是,这个函数只可以用来获取控件的屏幕坐标。即使用它也还是不能在控件上画出该点。对了,转换呀,我们可以用ScreenToClient,用这个函数可以将控件的坐标lpRect转换成以对话框左上顶点为原点的控件客户区坐标。 这样,就和传入的CPoint的坐标一致了。
真是搞的,微软何不提供一个直接获取控件在对话框客户区中的位置坐标呢,非要这么绕干嘛呢!
2. 第四句和第五句的问题,获取该控件的DC,然后画图,这是人的正常思维,可是微软不这么干,如果像上面这么画,将什么也画不出来,按照微软的想法,只有客户区才能画图,所以,还是要先老老实实的得到客户区的DC,可是,对话框程序中的客户区就是对话框本身呀,唉,没办法,还是先得到这个客户区吧。
CClientDC dc(this); 这里应该明白前面的控件和传入点为什么都要用以对话框左上顶点为原点的客户区坐标了吧。这样就可以让对话框DC来画它们了。
上面这段代码可以修改为如下:
CRect lpRect;
CStatic *m_static = (CStatic*)GetDlgItem(IDC_STATIC1);
m_static->GetWindowRect(&lpRect);
ScreenToClient(&lpRect);
CClientDC dc(this);
dc.MoveTo(CPoint point);
dc.LineTo(CPoint point);
.......
MFC中,class CRect : public tagRECT类的一个成员函数,作用是判断参数中给出的点是否在矩形区域内。returns TRUE if point is within rectangle。
[函数原型] BOOL PtInRect( POINT point ) const throw( ); [声明] Declare Function PtInRect Lib "user32" (lpRect As RECT, pt As POINTAPI) As Long [说明] 这个函数判断指定的点是否位于矩形lpRect内部 [参数表] point ------------- POINTAPI,欲判断的点 [返回值] Long,非零表示点在矩形内部,零表示点在矩形外部。会设置GetLastError [其它] 如点位于矩形四边之内,或矩形的顶部或左侧边线上,则认为它在矩形内部。如位于矩形的右侧或底部边线,则不认为它在矩形内部