VC 点滴 之 重绘

  基本知识:
1. OnPaint OnDraw 函数
View 的父类的 OnPaint 函数调用了 OnDraw 函数,若在子类为 WM_PAINT 消息添加响应函数 OnPaint OnDraw 函数将不会被调用。
2. CpaintDC CclietnDC
CpaintDC 的构造函数中调用了 BeginPaint(), 析构函数中调用了 EndPaint()
CclietnDC 的构造函数中调用了 GetDC(), 析构函数中调用了 ReleaseDC()
BeginPaint() EndPaint() 只能用于响应 WM-PAINT 消息,否则将会出错。
二、??????????? 利用动态数组:
1. 定义结构体 LINE ,用于保存线的数据。
struct LINE
{
?????? CPoint m_pt1;
?????? CPoint m_pt2;
};
2. View 中定义一个动态数组,保存每一根线的指针。
CPtrArray m_ptrLines;
    定义两个 Cpoint 的成员变量,保存线的起点和终点:
         ?? CPoint m_ptOld;
?????? CPoint m_ptNew;
3. View 中加入 WM_LBUTTONDOWN,WM_LBUTTONUP 的响应函数,在 OnLButtonDown 中为 m_ptNew 赋值,
       ??? m_ptOld=point;
4. OnLButtonUp 中加入代码:
      m_ptNew=point;
?????? CClientDC dc(this);
?????? ?????? ?????? dc.MoveTo(m_ptOld);
?????? dc.LineTo(point);
?????? ????????????? LINE *pLn=new LINE;
?????? pLn->m_pt1=m_ptOld;
?????? pLn->m_pt2=m_ptNew;
?????? m_ptrLines.Add(pLn);
5. OnDraw() 中加入:
int sum= m_ptrLines.GetSize();
for(int i=0;i 
{
?????? pDC->MoveTo(((Line *)m_ptrLines.GetAt(i))->m_pt1);
?????? pDC->LineTo(((Line *)m_ptrLines.GetAt(i))->m_pt2);
}
6. 加入滚动条:将 View cpp 文件和 h 文件中的 Cview 全部替换成 CscrollView
7. view 中加入虚函数 OnInitialUpdate() ,这个函数在 View 第一次刷新前被调用,在其中加入代码:
      SetScrollSizes(MM_TEXT,CSize(1024,768));
????????????? 这个函数也可在 View 的构造函数中调用。
8. OnLButtonUp 中生成 DC 后加入
OnPrepareDC(&dc);
?????? ?????? dc.DPtoLP(&m_ptOld);
?????? dc.DPtoLP(&m_ptNew);
三、??????????? 利用 CmetaFileDC 重绘
1. View 中定义成员变量:
?????? CMetaFileDC m_dcMetaFile;
2. View OnCreate 中加入代码:
m_dcMetaFile.Create();
3. View OnLButtonUp 中,注释有关数组的代码,加入:
m_dcMetaFile.MoveTo(m_ptOld);
m_dcMetaFile.LineTo(m_ptNew);
4. OnDraw()
?????? HMETAFILE hmetafile;
?????? hmetafile=m_dcMetaFile.Close();
?????? pDC->PlayMetaFile(hmetafile);
?????? m_dcMetaFile.Create();
?????? m_dcMetaFile.PlayMetaFile(hmetafile);
?????? ::DeleteMetaFile(hmetafile);
5. 保存文件:
加入菜单响应函数, OnFileSave, 加入代码:
?????? HMETAFILE hmetafile;
?????? hmetafile=m_dcMetaFile.Close();
?????? ::CopyMetaFile(hmetafile,"c://2.ddd");
?????? m_dcMetaFile.Create();
?????? m_dcMetaFile.PlayMetaFile(hmetafile);
?????? ::DeleteMetaFile(hmetafile);
6. 读出文件:
加入菜单响应函数, OnFileLoad, 加入代码:
?????? ?????? HMETAFILE hmetafile;
?????? ?????? hmetafile=::GetMetaFile("c://2.ddd");
?????? ?????? m_dcMetaFile.PlayMetaFile(hmetafile);
?????? ?????? ::DeleteMetaFile(hmetafile);
?????? Invalidate();
四、??????????? 利用兼容 DC 重绘:
1. View 中定义成员变量:
CDC??????? m_dcCompa;???
2. OnLButtonDown 中加入代码:
CClientDC dc(this);
?????? if(!m_dcCompa.m_hDC)
?????? {
????????????? m_dcCompa.CreateCompatibleDC(&dc);
????????????? CBitmap bmp;
????????????? CRect rect;
????????????? GetClientRect(&rect);
????????????? bmp.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
????????????? m_dcCompa.SelectObject(&bmp);
m_dcCompa.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
?????? }
?????? m_dcCompa.MoveTo(m_ptOld);
?????? m_dcCompa.LineTo(m_ptNew);
3. OnDraw 中加入:
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompa,0,0,SRCCOPY);
?
?
?
?
?
CWnd 对象在构造函数里成员被初始化为 0 。但 CPoint CRect 等在构造函数里成员没有做这种操作。 MFC 写的类一般在构造函数里要将成员初始化,除非它做了特殊说明
API 函数发出的消息是 SendMessage 方式。
?
CxxView 里画线,当我们画出图形后,修改了窗口的尺寸、覆盖了窗口、最小化、最大化这些操作后,由于窗口要重新显示出来,所以用窗口的定义好的画刷将窗口刷出来。窗口重绘后报告一个 WM_PAINT 通知你,并默认用父类的 OnPaint 响应该消息,父类的 OnPaint 要调用一个函数 OnDraw 。如果我们要把线在 OnDraw 里也画一遍的话,即使窗口重绘了,线还能看到,但是当我们覆盖了父类的 OnPaint ,发现线没有了。究其原因 CxxView OnPaint 没有为你调用 OnDraw 。我们可以跟踪进入查看父类的 OnPaint 的实现。其实我们也可以在子类的 OnPaint 里把线重画出来,但是最好是在 OnDraw 里重画,为什么呢?我们为 CxxView 覆盖一个虚函数 OnPrint( 安装一个打印机 ) ,发现它的父类也调用 OnDraw OnDraw 是一个虚函数,它的参数 DC 可以接受任何设备的 DC (这里可以接受打印机的 DC ,窗口的 DC 等, OnPaint 传窗口的 DC OnPrint 传打印机的 DC ),你对这个 DC 的操作就是在相对应的设备上输出,如输出到窗口或者输出到打印机,这样就可以让在 OnDraw 所写图形输出既能输出到窗口上又能输出到打印机上,实现了操作的统一性(虚函数的原理)和代码的复用性。
OnPaint 里为你产生了一个 CPaintDC, 它和 CClientDC 有什么区别能?
查看 CPaintDC 的说明。 CClientDC 的封装与之不同。
WinMain 程序里的 WM_LBUTTONDOWN WM_LBUTTONUP GetDC ReleaseDC 画线没问题,但用 BeginPaint EndPaint 画线出错。同样在 WM_PAINT 消息里不能用 GetDC ReleaseDC 画线,容易出错,所以 CPaintDC 只能在响应 WM_PAINT 消息的函数里使用, CClientDC 只能在响应非 WM_PAINT 消息的函数里使用。
An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function.
?
?????? ?????? case WM_PAINT:
???????????????????? HDC dc1;
???????????????????? //PAINTSTRUCT ps1;
???????????????????? //dc1=::BeginPaint(hwnd,&ps1);
???????????????????? dc1=::GetDC(hwnd);
???????????????????? ::TextOut(dc1,100,100,"hello world",strlen("hello world"));
???????????????????? //::MoveToEx(dc,20,20,NULL);
???????????????????? //::LineTo(dc,100,100);
???????????????????? //dc=::GetDC(hwnd);
???????????????????? //::MoveToEx(dc,x1,y1,NULL);
???????????????????? //::LineTo(dc,x2,y2);
???????????????????? ::ReleaseDC(hwnd,dc1);
???????????????????? //::EndPaint(hwnd,&ps1);
???????????????????? break;
????????????? case WM_LBUTTONDOWN:
???????????????????? x1=LOWORD(lParam);
???????????????????? y1=HIWORD(lParam);
???????????????????? break;
????????????? case WM_LBUTTONUP:
???????????????????? x2=LOWORD(lParam);
???????????????????? y2=HIWORD(lParam);???????????????????
???????????????????? HDC dc;
???????????????????? PAINTSTRUCT ps;
???????????????????? dc=::BeginPaint(hwnd,&ps);
???????????????????? //dc=::GetDC(hwnd);
???????????????????? ::MoveToEx(dc,x1,y1,NULL);
????????????????????
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值