这是我用的是对话框中的PICTURE控件,其实pictures控件就是一个静态文本控件。
我这个例子是基于对话框的。不是基于单文档应用程序的。
首先我们需要搞清楚两个VC中的坐标系。
窗口坐标=逻辑坐标=DC中实际画图函数用的坐标、比如moveto(),lineto()中的参数对应的都是逻辑坐标,画图用的。
视口坐标=设备坐标=物理坐标(一个坐标点对应一个像素,可以这么理解)实际显示器大小
坐标原点中设备原点位置是固定的,始终在窗口客户区的左上角,左上角的视口坐标(设备坐标)为(0,0)
dc.SetViewportOrg(m_rect.left,m_rect.bottom);
dc.SetWindowOrg(-400,4400);
解释一下这两个函数:其实我认为这两个函数都是用来设置逻辑坐标原点的,因为设备坐标原点位置是不动的。就是左上角的(0,0),所以大家一定要明确这个概念。
SetViewportOrg(x,y)这个是把视口坐标下的(x,y)点设置成逻辑坐标原点的。由于视口坐标系原点固定,所以我们确定逻辑坐标原点的位置,一般这个前提,最好默认SetWindowOrg(0,0)。
若SetViewportOrg(0,0)默认,SetWindowOrg(x,y)的意思是:视口坐标原点(0,0)就是逻辑坐标下的(x,y)点。从而可以反推出,逻辑坐标原点。要牢记设备原点坐标在窗口DC区的左上角。
dc.SetViewportExt(X1,Y1);
dc.SetWindowExt(X2,Y2);
这两个函数,我认为是用来设置视口坐标和逻辑坐标比例关系的。已知视口坐标系的方向,即X轴向右为正,Y轴向下为正。设X1,Y1为正,若Y2与Y1符号相反,则认为窗口坐标的Y轴正方向与视口坐标的相反,即向上,从而坐标系就可以转换成我们常用的模式,X向右为正,Y向上为正。
下面是实现的具体过程:
第一步:先放置一个pictures控件,并新建一个CStatic的派生类,我取名叫CMyPic,这个类是用来在pictures控件上画图的。把pictures控件关联成CMyPic类的对象m_pic。
第二步:在对话框的OnInitDialog()添加如下代码,注意这段代码不能添加在Onpaint()函数中的
m_pic.GetWindowRect(&rect);
ScreenToClient(&rect);
第三步:添加WM_TIMER消息处理函数OnTimer(UINT nIDEvent) 。添加如下代码
m_pic.DrawAxis();
m_pic.DrawPoint()//注意这两个函数是在你新建的那个派生类定义的方法,是你具体画图的方法,
第四步:在新建类CMyPic中增加Onpaint响应函数,并在其中设置坐标比例模式,和构建虚拟内存DC,注意不要在对话框这个类中的Onpaint函数中添加画图函数,没用的,而且会造成闪烁。因为Onpaint()函数中自动调用擦屏函数,从而造成闪屏,我们这里的方法是在控件对象m_pic所对应的类中重载Onpaint函数。
CPaintDC dc(this); // 这里返回的DC既是当前picture控件所对应的客户区大小,既实际的dc设备
GetClientRect(&m_rect); //获得实际设备dc的视口坐标,注意是视口坐标
m_width=m_rect.Width();//长宽都是视口坐标下的
m_height=m_rect.Height();
dc.SetMapMode(MM_ANISOTROPIC);
dc.SetViewportExt(m_width,m_height);
dc.SetWindowExt(6800,-5200);
dc.SetViewportOrg(m_rect.left,m_rect.bottom);
//纠缠我的难题:若要自定义比例模式,不仅实际虚拟DC要设置,原来的实际的DC也要设置相同的比例模式,红色标出即为虚拟内存m_memDC和实际dc设置比例模式
if (m_memDC.m_hDC==NULL)
{
m_nYmargin = (int)(0.1*m_rect.Height());
CBitmap bmp;
CBitmap* pOldBmp;
m_memDC.CreateCompatibleDC(&dc);
bmp.CreateCompatibleBitmap(&dc,m_width,m_height);
pOldBmp=m_memDC.SelectObject(&bmp);
m_memDC.SetMapMode(MM_ANISOTROPIC);
m_memDC.SetViewportExt(m_width,m_height);
m_memDC.SetWindowExt(6800,-5200);
m_memDC.SetViewportOrg(m_rect.left,m_rect.bottom);
//m_memDC.FillSolidRect(0,0,6000,4000,RGB(123,213,132));默认是黑色背景
DrawAxis();
}
dc.BitBlt(0,0,6800,5200,&m_memDC,0,0,SRCCOPY);
所以虚拟内存m_memDC要和原实际都要设置比例模式,而且要一致。才能保证后面在虚拟内存中画完后可以通过bitblt函数搬移到视口区。
dc.BitBlt(0,0,6800,5200,&m_memDC,0,0,SRCCOPY); 的第三个第四个参数是逻辑坐标。还有就是第一个和第二个参数我还没搞明白。
第五步,就是新建m_pic的画图函数了:以void CMyPic::DrawAxis()为例。
void CMyPic::DrawAxis() { CPen PenGreen; PenGreen.CreatePen(PS_SOLID,1,RGB(0,255,0)); m_memDC.SelectObject(&PenGreen); m_memDC.MoveTo(400,800); m_memDC.LineTo(400,4800);//从左上角到右下角的一条绿色直线 m_memDC.MoveTo(400,4800); m_memDC.LineTo(6400,4800); m_memDC.MoveTo(6400,4800); m_memDC.LineTo(6400,800); m_memDC.MoveTo(6400,800); m_memDC.LineTo(400,800); CPen PenDASH; PenDASH.CreatePen(PS_DOT,1,RGB(127,127,127)); m_memDC.SelectObject(&PenDASH); int i; for(i=600;i<6400;i=i+200) { m_memDC.MoveTo(i,800); m_memDC.LineTo(i,4800); // CString cs; // cs.Format("%2.1f",j/10) // pDC->TextOut(100,0,cs); } CPen Pen2; Pen2.CreatePen(PS_SOLID,1,RGB(127,127,127)); m_memDC.SelectObject(&Pen2); for(i=1200;i<4800;i=i+400) { m_memDC.MoveTo(400,i); m_memDC.LineTo(6400,i); } }
在保证第四步设置正确的情况下,我们才可以用逻辑坐标画出正确图,并用bitblt搬移。我上个简单的图:最后,你可以自己加一个按钮控件,用来启动定时器,SetTimer(1,100,null)我就不说了。