在OnPaint中必须调用一次BeginPaint和EndPaint,且也只能调用一次

2024-06-08 03:08

本文主要是介绍在OnPaint中必须调用一次BeginPaint和EndPaint,且也只能调用一次,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于对话框的程序(mfc默认生成),重载OnEraseBkgnd函数,其它不动,若在OnPaint函数中不调用其基类的OnPaint函数,即注释掉CDialog::OnPaint();,代码如下:

[cpp] view plaincopyprint?

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. }  


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

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

 

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

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

 

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

 

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

 

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

 

这篇关于在OnPaint中必须调用一次BeginPaint和EndPaint,且也只能调用一次的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041058

相关文章

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll