### vc++ 实现非窗口类中使用定时器的方法 在探讨如何在非窗口类中使用定时器之前,我们首先需要了解几个关键的概念:定时器、非窗口类以及它们与消息映射之间的关系。 #### 一、定时器简介 在Windows编程中,定时器是一个重要的功能,它可以帮助程序实现周期性的任务执行。Windows API提供了`SetTimer()`和`KillTimer()`两个函数来创建和销毁定时器。创建定时器后,系统会在指定的时间间隔发送`WM_TIMER`消息到指定的窗口过程。 对于窗口类来说,使用定时器非常直观简单。通常情况下,程序员会利用`SetTimer()`函数设置一个定时器,并且通过重写`CWnd`类中的`OnTimer()`成员函数来处理定时器事件。但是,在非窗口类中使用定时器则需要采取不同的方法。 #### 二、非窗口类中的定时器使用 非窗口类是指那些不继承自`CWnd`的类,因此这些类无法直接接收Windows消息。为了在非窗口类中使用定时器,我们需要绕过传统的消息映射机制。具体做法如下: 1. **定义非窗口类**: ```cpp class CNonWindowClass { public: CNonWindowClass(HWND hWnd); // 构造函数接受窗口句柄 void SetTimer(int nIDEvent, UINT uElapse); void KillTimer(int nIDEvent); void OnTimer(int nIDEvent); private: HWND m_hWnd; // 存储外部窗口句柄 }; ``` 2. **构造函数**: - 需要在构造函数中存储一个有效的窗口句柄,这个窗口将用于接收定时器消息。 ```cpp CNonWindowClass::CNonWindowClass(HWND hWnd) : m_hWnd(hWnd) {} ``` 3. **设置和销毁定时器**: - 使用`SetTimer()`函数创建定时器,并使用`KillTimer()`销毁定时器。这两个函数都需要传递一个窗口句柄。 ```cpp void CNonWindowClass::SetTimer(int nIDEvent, UINT uElapse) { ::SetTimer(m_hWnd, nIDEvent, uElapse, NULL); } void CNonWindowClass::KillTimer(int nIDEvent) { ::KillTimer(m_hWnd, nIDEvent); } ``` 4. **处理定时器消息**: - 由于非窗口类无法直接接收消息,我们需要在对应的窗口类中重写`OnTimer()`函数来处理定时器消息。这意味着我们需要在某个窗口类中实现以下代码: ```cpp void CMyWindow::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == IDT_MY_TIMER) // 假设IDT_MY_TIMER是定时器的ID { // 在这里调用非窗口类中的方法 m_nonWindowClass.OnTimer(nIDEvent); } CMyWindow::OnTimer(nIDEvent); // 调用基类的方法 } ``` 5. **非窗口类中的定时器处理函数**: - 这个函数可以用来实现定时需要执行的任务。 ```cpp void CNonWindowClass::OnTimer(int nIDEvent) { // 在这里执行定时任务 } ``` #### 三、静态成员变量的应用 除了定时器的实现之外,文章还提到了静态成员变量的应用。静态成员变量在类的所有实例之间共享同一份数据,这意味着一旦修改了静态成员变量的值,所有的实例都会看到相同的更改。 例如,我们可以定义一个静态字符串成员变量来表示公司的名称: ```cpp class CPerson { public: static CString szCompanyName; }; CString CPerson::szCompanyName = "ABC公司"; // 初始化静态成员变量 ``` 这样,每个`CPerson`对象都可以访问同一个公司名称。 在非窗口类中使用定时器的关键在于找到一个合适的窗口作为消息的接收者,并在该窗口的消息处理函数中调用非窗口类的相关方法。通过这种方式,即使是在非窗口类中也可以轻松地实现定时任务。
一、实现方法
在非窗口类中使用定时器,需要了解的知识比较多。首先非窗口类中没有消息映射,也没有象CWnd类具有的SetTimer()方法来设置定时器。没有消息映射,就只能靠我们自己定义的回调函数来处理定时器的消息,因此大家有必要了解一下回调函数的概念。因为回调函数只能用全局函数或静态成员函数来实现,而为了维持类的完整性,又需求使用类的静态成员函数来作为回调函数,所以我们又需要了解一下静态数据成员和静态成员函数的性质。又因为定时器是在我们的程式中产生的,这又需要来管理定时器,所以又用到了映射表类CMap,因此介绍一下CMap的简单用法也是必不可少的。
所谓回调函数就是按照一定的形式由研发人员定义并编写实现内容,当发生某种事件时由系统或其他函数来调用的函数。使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己编写的一个函数(也就是回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,也就是某种事情发生的时候,利用传递的函数地址调用回调函数,这时研发人员能利用这个机会在回调函数中处理消息或完成一定的操作。回调函数只能是全局函数,或是静态函数,因为这个函数只是在类中使用,所以为了维护类的完整性,我们用类的静态成员函数来做回调函数。
在C语言中,声明一个数据为静态类型,意味着该变量的生存周期是静态的,即在程式的开始时即分配,到程式终止时才释放。但在C++中,声明一个类中的成员为静态类型,则意味着该类的所有实例只有该成员的一个拷贝。也就是说,不管应用程式中创建了这个类的多少个对象,其静态成员只有一个副本,该副本为这个类的所有对象实例所共享,而对于非静态成员,每个类对象实例都有自己的拷贝。例如一个公司职员类的定义如下:
class CPerson
{
public:
CString szName;
static CString szCompanyName;
CPerson();
virtual ~CPerson();
};
对于同一家公司员工,每个人都有不同的姓名,不过他们的公司名字是相同的,所以就能用一个静态类型来保存,这样所有的员工都共享这个公司名称,只要一位员工更新了公司名称,则所有员工的公司名称就被更新了。
静态成员被当作该类类型的全局对象,能把一个静态数据成员和静态成员函数当成全局变量和函数那样去存储和访问,但又被隐藏在类的内部,并且清晰地和这个类相联系但又不是全局对象,同全局对象相比,使用静态成员有两个优势:
(1) 静态成员没有进入程式的全局名字空间,他属于类,他的名字只在类的范围内有效,因此不存在和程式中其他全局名字冲突的可能性。
使用静态数据成员能节省内存,因为他是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是相同,但他的值是能更新的。只要对静态数据成员的值更新一次,就能确保所有对象都能够访问到被更新后的值,这样能提高效率和节省内存空间。
在类中将一个成员变量声明为静态的,和声明普通变量的唯一差别就是在其定义前加一个static,象上面的例子中那样声明:static CString szCompanyName;静态数据成员显式初始化和一般数据成员初始化不同。静态数据成员显式初始化的格式如下:
<数据类型><类名>::<静态数据成员名>=<值>
对于上面的例子这样初始化:CString CPerson::szCommpanyName = "天极网";
这表明:
(1) 初始化在类体外进行,而前面不加static,以免和一般静态变量或对象相混淆。
(2) 初始化时不加该成员的访问权限控制符private,public等。
(3) 初始化时使用作用域运算符来标明他所属类,因此,静态数据成员是类的成员,而不是对象的成员。
在类的成员函数中能直接引用该类的静态数据成员,而不必使用成员访问操作符。不过在非成员函数中,我们必须以两种方式之一访问静态数据成员。
(1) 使用成员访问操作符。
例如:me是CPerson的一个实例,在非成员函数中能这样应用其中的静态数据成员:CString TheCommpanyName = me.CommpanyName;
(2) 因为类静态数据成员只有一个拷贝,所以他不一定要通过对象或指针来访问。方法二就是用被类名限定修饰的名字直接访问他。当我们不通过类的成员访问操作符访问静态数据成员时,必须指定类名及紧跟其后的域操作符,因为静态成员不是全局对象,所以我们不能在全局域中找到他。如:CString TheCommpanyName = CPerson::CommpanyName;
顺便说一句静态数据成员更有两个特点:一是静态数据成员的类型能是其所属类,而非静态数据成员只能被声明为该类的对象的指针或引用;二是静态数据成员能被作为类成员函数的缺省实参,而非静态成员不能。
静态成员函数的声明和普通函数的唯一差别就是在前面加一个static。通常,当前对象的地址(this)是被隐含地传递到被调用的非静态成员函数的。静态成员函数具有类的范围,同非静态成员函数相比,静态成员函数没有this参数,因此他不能访问一般的数据成员,而只能访问静态数据成员、枚举或嵌套类型和其他的静态成员函数。这样使用静态成员函数在速度上能比全局函数有少许的增长,他不仅没有传递this指针所需的额外的花费,而且更有使函数在类内的好处。如果静态成员函数中要引用非静态成员时,可通过对象来引用。我们能用成员访问操作符点(.)和箭头(->)为一个类对象或指向类对象的指针访问静态成员函数,也能用限定修饰名直接访问静态成员函数,而无需声明类对象。
静态成员函数遵循约束条件如下:(1) 不能用成员选择符(.或->)访问非静态成员;(2) 不能说明为虚函数;(3) 不能和有相同参数类型的非静态成员函同名;(4) 不能声明为const或volatile;(5) 出目前类体外的函数定义不指定关键字static。
剩余8页未读,继续阅读
- 粉丝: 0
- 资源: 8
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- Python爬虫案例,处理动态加载的内容,保存数据到SQLite数据库
- 空中俯视物体检测15-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord数据集合集.rar
- 基于前端Vue后端.NetCore Web后台管理系统通用开本框架采用前后端分离技术,前端使用vue2.6.0,后端使用.netcore3.1,支持跨平台、多租户、支持MySQL SQLServer
- html+css网页设计 美食 餐饮杰12个页面
- 2024级涉外护理7班马天爱劳动实践总结1.docx
- 基于纯verilogFPGA的双线性差值视频缩放 功能:利用双线性差值算法,pc端HDMI输入视频缩小或放大,然后再通过HDMI输出显示,可以任意缩放 缩放模块仅含有ddr ip,手写了 ram,f
- obsidian笔记软件常用插件离线包
- 【机器学习进阶】PyTorch CIFAR-10 训练与结果保存
- 文心快码 - Baidu Comate
- 大白菜病害图像数据集(2900张图片).rar
- DenseNet卷积神经网络网络【121,161,169,201四种版本】实现的图像识别项目实战:多类别鸟品种分类
- 基于PHP语言的图书管理系统,包括添加、删除、查询和更新图书信息的功能
- 2024级涉外护理7班马天爱劳动实践总结2.docx
- 基于Matlab实现BUCK仿真(程序).rar
- OpenGL使用TransformFeedback实现粒子效果
- 空中俯视物体检测16-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord数据集合集.rar
- 1
- 2
前往页