窗体重绘,图像更新
窗体重绘,图像更新
一、 画图后,用一个新类保存画图信息,然后在OnDraw中调用之前的方法,在窗口更新的时候用之前保存的绘图方法信息,重新绘制。
void CGraphicPlusView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); //选择一个透明画刷
dc.SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
dc.SetPixel(point,RGB(0,0,0));
break;
case 2:
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
break;
case 3:
dc.Rectangle(m_ptOrigin.x,m_ptOrigin.y,point.x,point.y);
break;
case 4:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
default:
break;
}
/*为了使拉动边框的时候能保持图像*/
CGraph* pGraph=new CGraph(m_ptOrigin,point,m_nDrawType); //此处将该对象保存到堆中,将对象所在的地址保存到pGraph中可以保证不会在本块语句结束时被析构
m_ptrArray.Add(pGraph); //将图像画法保存到集合类对象CPtrArray m_ptrArray中,当OnDraw()被调用的时候再进行输出。
CView::OnLButtonUp(nFlags, point);
}
void CGraphicPlusView::OnDraw(CDC* pDC)
{
CGraphicPlusDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CBrush* pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(pBrush);
for(int i=0;i<m_ptrArray.GetSize();i++)
{
switch(((CGraph*)m_ptrArray.GetAt(i))->m_nDrawType)
{
case 1:
pDC->SetPixel(((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd,RGB(0,0,0));
break;
case 2:
pDC->MoveTo(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin);
pDC->LineTo(((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd);
break;
case 3:
pDC->Rectangle(CRect(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin,
((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd));
break;
case 4:
pDC->Ellipse(CRect(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin,
((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd));
break;
default:
break;
}
}
}
二、 在窗口重绘的时候会发送WM_PAINT消息,但OnDraw函数并不是WM_PAINT的响应函数,其实OnPaint()函数是一个虚函数,其函数原形:
void OnPaint()
{
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
因此系统在发送WM_PAINT消息的时候同样会调用到OnDraw,因此,如果重写了OnPaint后,如果没有再包含OnDraw方法,它将不再被调用。[可以设置断点进行实验]
CPaintDC:
A CPaintDC object can only be used when responding to a WM_PAINT message, usually in your OnPaint message-handler member function.
由此可知,CPaintDC只能在WM_PAINT消息被调用的时候被使用。
设备上下文:(Device Context,DC)
设备上下文是一种包含有关某个设备(如显示器或打印机)的绘制属性信息的 Windows 数据结构。所有绘制调用都通过设备上下文对象进行,这些对象封装了用于绘制线条、形状和文本的 Windows API。设备上下文允许在 Windows 中进行与设备无关的绘制。设备上下文可用于绘制到屏幕、打印机或者图元文件。
CPaintDC 对象将 Windows 的常见固定用语进行封装,调用 BeginPaint 函数,然后在设备上下文中绘制,最后调用 EndPaint 函数。CPaintDC 构造函数为您调用 BeginPaint,析构函数则调用 EndPaint。该简化过程将创建 CDC 对象、绘制和销毁 CDC 对象。在框架中,甚至连这个过程的大部分也是自动的。具体说来,框架给 OnDraw
函数传递(通过 OnPrepareDC)准备好的 CPaintDC,您只需绘制到 CPaintDC 中。根据调用 OnDraw
函数的返回,CPaintDC 被框架销毁并且将基础设备上下文释放给 Windows。
CClientDC 对象封装对一个只表示窗口工作区的设备上下文的处理。CClientDC 构造函数调用 GetDC 函数,析构函数调用 ReleaseDC 函数。CWindowDC 对象封装表示整个窗口(包括其框架)的设备上下文。
CMetaFileDC 对象将绘制封装到 Windows 图元文件中。与传递给 OnDraw
的 CPaintDC 相反,在这种情况下您必须自己调用 OnPrepareDC。
鼠标绘图
框架程序中的大多数绘图(由此,大部分设备上下文参与)都在视图的 OnDraw
成员函数中完成。但是,您仍然可以将设备上下文对象作其他用途使用。例如,若要在视图中提供鼠标运动的跟踪回馈,只需直接绘制到视图中而无需等待调用 OnDraw
。
在这种情况中,可以使用 CClientDC 设备上下文对象直接绘制到视图中。
三、 向继承于CView的类添加滚动条功能。
1、 先替换所有的CView为CScrollView
2、 但只这样做将会出现编译错误,这时候需要写虚函数virual void InitialUpdate()
void CGraphicPlusView::OnInitialUpdate() //在一个窗口完全创建后,第一个运行的方法,比OnDraw还靠前
{
CScrollView::OnInitialUpdate();
// TODO: 在此添加专用代码和/或调用基类
SetScrollSizes(MM_TEXT,CSize(800,600)); //通过该方法设置一个滚动背景的大小
}
3、 编译通过。测试:在区域内画图,将滚动条拉至底部,在最下角落画图,拉回滚动条至顶部,切换页面(调用OnDraw函数),发现最右下角的图片跑到上面去了。
原因:因为逻辑坐标和设备坐标没有对应起来。
解决方法:在OnLButtonDown画完后,保存画图信息之前,调用
/*为了使滚动条拖动的时候设备坐标能够自动转化为逻辑坐标*/
OnPrepareDC(&dc); //调整显示上下文的属性,重新设置逻辑坐标的原点
dc.DPtoLP(&m_ptOrigin); //设备坐标转化为逻辑坐标
dc.DPtoLP(&point);
//之后再进行保存m_ptOrigin,point的时候就是经过变换后的值,在重绘的时候将会通过公式算出来。
四、 CMetaFileDC类
Remarks
A Windows metafile contains a sequence of graphics device interface (GDI) commands that you can replay to create a desired image or text.
To implement a Windows metafile, first create a CMetaFileDC object. Invoke the CMetaFileDC constructor, then call the Create member function, which creates a Windows metafile device context and attaches it to the CMetaFileDC object.
Next send the CMetaFileDC object the sequence of CDC GDI commands that you intend for it to replay. Only those GDI commands that create output, such as MoveTo and LineTo, can be used.
After you have sent the desired commands to the metafile, call the Close member function, which closes the metafile device contexts and returns a metafile handle. Then dispose of the CMetaFileDC object.
CDC::PlayMetaFile can then use the metafile handle to play the metafile repeatedly. The metafile can also be manipulated by Windows functions such as CopyMetaFile, which copies a metafile to disk.
When the metafile is no longer needed, delete it from memory with the DeleteMetaFile Windows function.
定义一个对象m_dcMetaFile,代替先前的dc而存在。
并且在构造函数中调用Create方法创建一个空对象。
m_dcMetaFile.Create();
在OnDraw中
/*CMetaFileDC*/
HMETAFILE hmetaFile; //创建一个句柄
hmetaFile=m_dcMetaFile.Close(); //储存返回的句柄
pDC->PlayMetaFile(hmetaFile); //在pDC中显示之前保存的metafile信息
m_dcMetaFile.Create(); //再创建一个新的metafiledc对象,然后供应下一次画图的调用
m_dcMetaFile.PlayMetaFile(hmetaFile); //把上一次的图像与新画的图像保存在一起,使之前的图像不会丢失
DeleteMetaFile(hmetaFile); //销毁已经的句柄资源
/*CMetaFileDC*/
五、 CDC:Compatible利用兼容位图来保存再显示
OnLButtonUp()与OnDraw()
if(!m_dcCompatible.m_hDC) //只有第一次创建的时候需要创建,之后就不用再创建了
{
m_dcCompatible.CreateCompatibleDC(&dc);
CRect rect;
GetClientRect(&rect);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height()); //使用兼容位图来代替普通位图
m_dcCompatible.SelectObject(&bitmap);
m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY); //但是兼容位图不同于普通位图,会丢失一些颜色等信息,因此要在此手动选入
m_dcCompatible.SelectObject(pBrush);
}
之后与先前相同将dc/m_dcMetaFile的位置换为m_dcCompatible
在OnDraw()
/*利用兼容位图CDC::m_dcCompatible*/
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);
/*利用兼容位图CDC::m_dcCompatible*/
posted on 2008-07-18 20:08 volnet(可以叫我大V) 阅读(4124) 评论(1) 编辑 收藏 举报