在OnPaint中必须调用一次BeginPaint和EndPaint,且也只能调用一次。(上) .

简介: 基于对话框的程序(mfc默认生成),重载OnEraseBkgnd函数,其它不动,若在OnPaint函数中不调用其基类的OnPaint函数,即注释掉CDialog::OnPaint();,代码如下: [cpp] view plaincopyprint? void CDDDDlg...
基于对话框的程序(mfc默认生成),重载OnEraseBkgnd函数,其它不动,若在OnPaint函数中不调用其基类的OnPaint函数,即注释掉CDialog::OnPaint();,代码如下:
  1. void CDDDDlg::OnPaint()  
  2. {  
  3.     if (IsIconic())  
  4.     {  
  5.         CPaintDC dc(this); // device context for painting   
  6.   
  7.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  8.   
  9.         // Center icon in client rectangle   
  10.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  11.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  12.         CRect rect;  
  13.         GetClientRect(&rect);  
  14.         int x = (rect.Width() - cxIcon + 1) / 2;  
  15.         int y = (rect.Height() - cyIcon + 1) / 2;  
  16.   
  17.         // Draw the icon   
  18.         dc.DrawIcon(x, y, m_hIcon);  
  19.     }  
  20.     else  
  21.     {  
  22.         //CDialog::OnPaint();   
  23.     }  
  24. }  
void CDDDDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { //CDialog::OnPaint(); } }


 则执行后界面没有问题,如下图:

但是,如果将此界面隐藏后再显示,则上面的控件都不能显示了,如下图:

 

跟踪程序会发现,第一次生成界面时候,进入过OnCtlColor函数(TRACE("OnCtlColor\n");语句输出),

当隐藏界面再显示后,就再也没进过OnCtlColor函数。当然看不见原先界面的控件了,因为根本没有重绘出来。原因见下篇

 

 

 

A:在OnPaint中注释此句CDialog::OnPaint();为什么会不停地调用OnPaint函数呢(不断执行TRACE("OnPaint\n");语句)?

 

Q:如果自己的OnPaint代码什么也没做的话(至少没有声明过CPaintDC类型的变量),还必须调用一下CDialog::OnPaint,否则BeginPaint和EndPaint就没有办法被调用了。
总之,在响应WM_PAINT消息的时候,必须调用一遍BeginPaint和EndPaint。调用的方法有三种:
1、声明一个CPaintDC类型的变量(即使你什么也不画),CPaintDC的构造函数就是调用BeginPaint,析构函数就是调用EndPaint。
2、调用基类的OnPaint(实际上就是调用API的DefWindowProc,它会自动调用BeginPaint和EndPaint)。
3、自己直接调用BeginPaint和EndPaint。
上述三种方法,必须选择其一,而且也只能选择其一(因为在一个WM_PAINT消息内不能调用两次BeginPaint和EndPaint)。

 

正如我猜想的,因为你调用了CDialog::OnPaint();
你把这句注释掉就可以了。
所以说凡事总有因果,CDialog::OnPaint()调用默认的窗口过程来绘制,也会调用BeginPaint/EndPaint()。而这两个函数的作用,是获取DC、剪裁区域和从消息队列中移走WM_PAINT消息(因此,如果不用上述三种方法的一种调用一遍BeginPaint和EndPaint的话,WM_PAINT消息就不会从消息队列里面移走,系统就会不停的发送WM_PAINT,这就是问题中所提到的不停的调用OnPaint函数的原因了)。这两个函数,必须在WM_PAINT消息中调用,而且只能调用一次!

 

相关帖子:

http://topic.csdn.net/u/20100801/11/40897468-807e-445a-a817-ede00dfd406e.html

 

http://topic.csdn.net/u/20080620/15/1D8E30FD-584A-4551-B93A-DA97D5F6423C.html#r_50392023

 

目录
相关文章
|
11月前
|
Java Maven Spring
SpringBoot项目创建失败或无法启动,启动报错时的常见问题及解决方案
文章列举了在IDEA中创建Spring Boot项目时可能遇到的常见问题及其解决方案,如项目不被识别为Maven项目、依赖未找到或报红、JDK版本不一致和POM文件中的Jar包下载失败等问题。
2871 0
SpringBoot项目创建失败或无法启动,启动报错时的常见问题及解决方案
|
自然语言处理 搜索推荐 机器人
langchain 简介
langchain 简介
821 1
|
机器人 Linux API
基于Ollama+AnythingLLM轻松打造本地大模型知识库
Ollama是开源工具,简化了在本地运行大型语言模型(ile优化模型运行,支持GPU使用和热加载。它轻量、易用,可在Mac和Linux上通过Docker快速部署。AnythingLLM是Mintplex Labs的文档聊天机器人,支持多用户、多种文档格式,提供对话和查询模式,内置向量数据库,可高效管理大模型和文档。它也是开源的,能与Ollama结合使用,提供安全、低成本的LLM体验。这两款工具旨在促进本地高效利用和管理LLMs。
155432 32
|
Oracle 关系型数据库
Oracle 语句的执行顺序
1、FROM 子句:执行顺序为从后往前、从右到左。数据量较少的表尽量放在后面。 2、WHERE子句:执行顺序为自下而上、从右到左。将能过滤掉最大数量记录的条件写在WHERE 子句的最右。 3、GROUP BY:执行顺序从左往右分组,最好在GROUP BY前使用WHERE将不需要的记录在GROUP BY之前过滤掉。 4、HAVING 子句:消耗资源。尽量避免使用,HAVING 会在检索
2419 0
|
机器学习/深度学习 存储 人工智能
生成式 AI 与 LangCHain(二)(3)
生成式 AI 与 LangCHain(二)
513 3
|
小程序 C++
【微信小程序-原生开发】实用教程19 - 表单范例 VS 表单校验(含必填校验函数封装,实时数字校验)
【微信小程序-原生开发】实用教程19 - 表单范例 VS 表单校验(含必填校验函数封装,实时数字校验)
239 0
|
存储 算法 C++
一篇文章让你熟悉unordered_map及其模拟实现(下)
unordered_map哈希策略函数 1. load_factor float load_factor() const noexcept; load_factor 函数用于获取当前
|
存储 SQL 关系型数据库
GIS系统中WKT、SRID、EPSG概念解析
之前一直对WKT、EPSG、SRID不是很理解,总是混淆,今天看了一下,清晰了很多,顺便总结一下。
875 0
|
搜索推荐 前端开发 数据可视化