VC++讲义 第13章

VC++讲义 第13章
VC++讲义 第13章

第14章 ActiveX技术

ActiveX技术的前身是OLE技术是Microsoft为了适应Internet的发展对OLE进行的扩展(当时的含义是“Activeate the Internet”),当时只是为了发展一种小型的可从网络上快速下载的可重用组件。但是随着ActiveX技术的发展ActiveX很快成为了Microsoft 新的口号。ActiveX由定义WEB页面到OLE控件的所有内容发展到定义一种可重用组件技术的规范,现在ActiveX已经成为一种概念和潮流。本章将介绍什么是ActiveX控件及怎样制作一个ActiveX控件。

14.1 ActiveX简介

ActiveX的基础是OLE和COM,并使用COM的接口和交互模型使ActiveX控件进行完全无缝的集成。COM技术定义了构建ActiveX对象的方法及设计ActiveX接口的方式。但是通过Microsoft的各种开发工具可以屏蔽掉COM模型中许多另人费解的技术细节。ActiveX组件技术包括以下一些方面:

●自动化服务器

●自动化控制器

●控件

●COM对象

●文档

●容器

ActiveX控件是一组封装在COM(Component Object Model,组件对象模型)对象中的功能模块。这个COM对象是独立的,尽管它不能单独运行。ActiveX控件只能在ActiveX容器中运行。

我们知道,在WORD中可以插入或链接一个Excell表格,而在WORD环境下,如果我们要修改这个表格,还是要调用Excell应用程序。在这种情况下,WORD就好比是容器应用程序,而Excell就是服务器应用程序。

ActiveX控件提供了一系列的接口,容器应用程序用这些接口来触发控件中的各种功能模块。这些接口中有许多用来触发控件或容器应用程序中的事件。其他的接口则用于指定控件的属性页或用于传达控件是否处于活动状态。总之,在大多数ActiveX控件中内置了如此之多的接口,如果您自己为每一个接口的功能编写代码,可能需要花费大量的时间,幸运的是,Visual C++的AppWiard和ClassWizard可自动编写这些功能中的大部分代码,使您能够把注意力集中在控件应具有的特定功能上。

创建ActiveX控件过程中,仍然必须自己计划的是控件的属性、方法和事件。可以通过ClassWizard把这些要素添加到控件中,但如果任何属性或事件要求有特殊的代码,就必须手工编写有关的代码。对于要加入到控件中的任何方法,必须提供所有的代码,ClassWizard 会添加环境结构和代码,以便容器应用程序能浏览和调用该方法,正如它会加入所有必要的代码,以调用应用程序的任何一个事件处理程序。

14.2 ActiveX控件和普通Windows控件

ActiveX控件是一个可以插入到应用程序中的一个小组件,和普通的Windows控件一样,至少在表面上是一样的,但它们毕竟不是一回事,ActiveX控件有自己的特点。

14.2.1 ActiveX控件和普通Windows控件的相同点

和普通的Windows控件一样,ActiveX控件也是一个子窗口,通常是对话框的子窗口。如果要在对话框中加入一个ActiveX控件,则与加入一个普通的Windows控件一样,只要在对话框编辑器中,将ActiveX控件放在适当的位置,并在资源面板中表示该ActiveX控件即可。如果要在程序运行中动态的建立ActiveX控件,则可以调用响应类的Create成员函数,可以像操作普通windows控件一样,调用C++类的成员函数来操作普通的ActiveX控件,包

含ActiveX控件得窗口称为包容器。

14.2.2 ActiveX控件和普通Windows控件的相同点

ActiveX控件最突出的特点是它的属性和方法。操作控件时调用的成员函数,实际上都与控件的属性方法有关。

控件都有符号化的名字对应着内部整数索引,用户通过这个整数索引及相应的值来设置一个控件的属性值,也可以用整数索引来获取相应控件的整数值。在特定的情况下,ClassWizard允许应用程序客户区类的成员变量,与窗口的某个控件相关联,通过DDX函数实现控件属性值与窗口成员变量之间的数据交换。

ActiveX控件的方法与函数非常相似。一个方法有符号化的名字,同时还有一组参数和一个返回值。可以通过调用控件类的成员函数来调用控件的方法,控件的编写者可以根据需要定义各种方法。

ActiveX控件不象普通的控件那样,发送以WM打头的通知消息给它的包容器窗口,而是“激发事件”。一个事件有一个符号化的名字及一组任意次序的参数。像普通控件通知消息一样,事件并没有返回值传递给ActiveX控件。事件的例子有Click(单击),KeyDown 等。对于用户来说,事件与控件通知消息是一样的。

在MFC中,ActiveX控件就像个子窗口一样,但在控件窗口和包容器窗口之间有一层重要的代码,实际上ActiveX控件甚至可以没有窗口。当调用Create函数时,并不是直接建立一个ActiveX控件窗口,而是载入控件代码,并发出一个“实地激活”命令。然后,ActiveX 控件才建立自己的窗口,而且通过MFC的CWnd类指针,可以访问该窗口。

在一般情况下,一个或多个ActiveX控件会保存在一个动态链接库中,但这种动态链接库的文件扩展名通常为OCX,而不是DLL。包容器通过Windows注册表,利用COM技术在需要的时候动态的载入动态链接库。

下一节会分别在具体的介绍ActiveX控件的属性、方法和事件。

14.3 ActiveX控件的属性、方法和事件

14.3.1 ActiveX控件的属性

属性是指控件中可见、并能被容器应用程序经常修改的那些属性。四种基本的属性类型是:环境(ambient)、扩展(extended)、库存(stock)和定制(custom)。环境属性由容器应用程序提供给控件(如要用的背景颜色、缺省字体)使控件看上去就像是容器应用程序的一部分。扩展属性实际上并不是控件的属性,而是由应用程序提供并实现的属性(如选项卡顺序),控件可以对这些属性做一定的扩展。库存属性由ActiveX控件开发工具实现,如控件字体或控件的背景色。最后一种属性类型,即定制属性,是很重要的属性,因为这些属性是您自己创建的ActiveX控件专有的,并且它们直接与控件的功能有关。

可以使用Class Wizard的Automation选项卡上的Add Property按钮来添加所需的任何属性。当通过Class Wizard向控件中添加新的属性时,应指定该属性所具有的多个特征。

第一个特征是属性的外部名称,这是显示给属性的容器应用程序的名称。另一个要指定的特征是代码中使用的变量的内部名称,但只有在该属性作为成员变量来实现时才需要此特征,还需要指定该属性的变量类型。

当指定属性是作为成员变量实现时(属性是该控件类的成员变量),则可以指定通知函数的名称,在容器应用程序对属性进行修改时调用此通知函数。如果属性不是控件类的成员变量,则必须指定通过Get和Set方法更改和查看该属性;这时容器应用程序通过调用Get 方法来获取属性的当前值,而通过调用Set方法来更改属性值。如果属性是通过Get和Set 方法来维护的,则可以指定这两种方法的名称。

对于属性的所有这些特征,Add Property对话框会输入属性的外部名称后建议一个合适的名称。如果打算接受缺省的名称,那么所需要指定的就只有外部名称、类型,以及该属

性是否是一个成员变量和是否使用Get和Set方法。如果从可用的库存属性列表中选择一个库存属性,那么其余的要素可自动指定。一旦指定了所有这些信息,Class Wizard就会向该控件项目添加所有必要的代码和变量。

14.3.2 ActiveX控件的方法

方法是控件中得能够被容器应用程序调用的函数。之前说过,ActiveX控件提供了一系列的接口(包括Idispatch接口),容器应用程序用这些接口来触发控件中的各种功能模块。其中,便可以通过Idispatch接口,使ActiveX控件的方法能被其他应用程序使用。鉴于IDispatch用来调用控件中的方法的方式,传递给该方法的变量必须封装在一个传给该控件的数据结构中。该数据结构与机器无关,因此不论控件是运行在装有Windows95/98平台的Inter Pentium Ⅱ上,还是运行在MIPS或Alpha处理器的Windows NT平台上,该数据结构看上去都上一样的。把有关参数进行必要的转换,以使它们与该数据结构正确匹配或把它们从该数据结构中提取出来,这是函数调用各方的责任。这种封装方法参数的过程称之为编组。

当通过Class Wizard的Automation选项卡上的Add Method按钮来添加新方法时,Class Wizard会加入所有必需的代码,以完成参数的编组以及所有其他支持功能,包括建立Idispatch接口和Idispatch表。

当通过Class Wizard向控件添加新方法时,需要输入容器应用程序调用的方法的外部名称。Class Wizard会提供一个缺省的内部名称,可以通过键入自己的内部名称来替代此缺省名称。必须指定的控件方法的其他特征是方法的返回类型和方法的参数。一旦完成了所有这些信息的输入,Class Wizard就会把所有必需的代码添加到控件中。

14.3.3 ActiveX控件的事件

事件是发送给容器应用程序的通知消息。它们用于通知应用程序某种事件已经发生,然后应用程序可在需要时对该事件采取相应的措施。从控件中可触发两种类型的事件:库存或定制事件。库存事件通过ActiveX控件开发工具来实现,可以在控件内以函数调用的方式使用。这些库存事件可使您触发容器应用程序中的鼠标或键盘事件、错误或状态变化。

除了库存事件外,还可以向控件中添加自己的可在容器应用程序中触发的定制事件。这些事件应该和控件中的特定的功能相关联。可以指定与事件一起传递给容器应用程序的参数,这样应用程序就能得到所需要的数据,以便对事件消息做出响应。

当需要触发这些事件中的任意一个时,所要做的一切就是调用触发该事件的内部事件函数,并把所有必要的参数传递给该函数。Class Wizard应该已添加了所有必要的代码,以便从内部函数的调用中触发事件消息。

我们可以通过Class Wizard的ActiveX Events选项卡上的Add Event按钮来添加需要的事件。

14.4 创建ActiveX控件

本节将通过一个实例来讲述如何编写一个ActiveX控件。本节编写的ActiveX控件用来显示系统时钟,该ActiveX控件具有前景色和背景色等属性,以及一些其他的方法和事件。完整例程请参见光盘中的例子代码EX14_00,具体操作步骤如下:

步骤1:创建ActiveX控件应用程序外壳。

启动Visual C++,选择新建工程,之前我们创建的最多的工程就是MFC AppWizard和Win32 Console Application工程,在这里,我们在新建工程对话框的左边列表中选择MFC ActiveX ControlWizard,在右边输入工程名为EX14_00,如图14-00所示。单击ok按钮,弹出MFC ActiveX ControlWizard-step 1 of 2对话框,该对话框询问用户要在该工程中添加多少个控件、控件是否具有运行时间许可证以及工程中是否包含注释及帮助文件等信息,如图14-01所示。

图14-00 新建ActiveX控件工程

图14-01 MFC ActiveX ControlWizard-step 1 of 2对话框运行时间许可证是一种确保控件使用者已购买了使用控件的许可证的手段。为卖给软件开发商而开发的控件一般带有运行时间许可证。许可证能防止那些没有付钱买控件的用户使用控件。当在一个应用程序中使用控件时,该控件的运行时间许可证由安装例程安装到用户

注册表中或运行时间许可证被编译到应用程序里。这些手段可以防止有人使用控件来建立新的应用程序。

本例程中采用默认设置,即创建一个ActiveX控件并且不具有运行时间许可证等。单击Next按钮,弹出MFC ActiveX ControlWizard-step 2 of 2对话框,单击该对话框上的Edit Names按钮可以修改默认的和工程名相同的控件的名称,例如本例中就将默认的EX14_00名称改为Time,这样更形象一些,如图14-02所示。最后单击Finish按钮。

图14-02 MFC ActiveX ControlWizard-step 2 of 2对话框现在就可以运行该工程来测试一下刚刚创建的ActiveX控件,由于ActiveX控件不能够单独运行,只能运行在容器应用程序中,因此,运行该工程之后会弹出如图14-03所示的对话框询问用户选择哪个可执行文件来测试该ActiveX控件。这里我们可以单击编辑框后面带有向右箭头的按钮,选择V C开发包中的ActiveX Control Test Containe。

图14-03 选择测试控件的容器

选择ActiveX Control Test Containe之后,单击ok按钮,启动如图14-04所示的ActiveX Control Test Containe程序界面,选择Edit|Insert New Control菜单项,在弹出的Insert Control对话框中,找到Time Control,然后单击ok按钮就可以了,如图14-05

所示。注意,Time就是我们自己创建的ActiveX控件。

图14-04 ActiveX Control Test Containe程序界面

图14-05 Insert Control对话框

最终运行的结果如图14-06所示,我们发现,显示的ActiveX控件只是一个椭圆,不错,这就是在我们没有添加任何代码的前提下,系统自动为我们生成的ActiveX控件的模样。除此之外,系统还为我们生成了一些类和接口,在工作台的ClassView页面中可以看到,如图14-07所示。

那么系统是在哪里为我们的控件添加椭圆模样的呢,是在类CTimeCtrl中的OnDraw函数中。然而,我们并不需要什么椭圆,我们要显示系统时钟,因此,要修改OnDraw函数。 步骤2:在CTimeCtrl类的OnDraw函数中显示时钟。

将OnDraw函数中的画椭圆的代码去掉,添加如下显示当前时间的代码:

void CTimeCtrl::OnDraw(

CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) {

// TODO: Replace the following code with your own drawing code.

CTime tm=CTime::GetCurrentTime();

CString str=tm.Format("%H:%M:%S");

pdc->TextOut(0,0,str);

}

图14-06 默认生成的ActiveX控件

图14-07 系统自动生成的接口和类

再运行,测试一下这个控件,的确它显示了当前的系统时间,但它并没有真正随着系统时间的改变而改变,它始终都在显示那一时刻的时间。为了让它实时的显示当前的时间,我们至少应该在工程一启动时创建一个计时器,并在计时器消息响应函数中显示时间。

步骤3:解决时钟不能自动更新。

为控件响应WM_CREATE和WM_TIMER事件,即在CTimeCtrl类中添加WM_CREATE和WM_TIMER消息响应函数OnCreate、OnTimer(通过鼠标右击CTimeCtrl类,在弹出的快捷方式菜单中选择Add Windows Message Handler来添加)。分别编写代码如下:int CTimeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (COleControl::OnCreate(lpCreateStruct) == -1)

return -1;

// TODO: Add your specialized creation code here

SetTimer(1,1000,NULL); //设置计时器

return 0;

}

void CTimeCtrl::OnTimer(UINT nIDEvent)

{

// TODO: Add your message handler code here and/or call default

InvalidateControl(); //实际上是调用CTimeCtrl::OnDraw()函数

COleControl::OnTimer(nIDEvent);

}

●步骤4:我们希望时钟的背景色同容器的背景色一致,那么修改OnDraw函数中的代码,

如清单14-00所示:

清单14-00 CTimeCtrl::OnDraw函数代码———————————————————————————————————————

1 void CTimeCtrl::OnDraw(

2 CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

3 {

4 // TODO: Replace the following code with your own drawing code.

5 //定义画刷

6CBrush brush(TranslateColor(GetBackColor()));

7//将时钟背景改为透明模式

8pdc->SetBkMode(TRANSPARENT);

9//定义画刷的矩形范围,rcBounds值是OnDraw函数中的参数,由系统传来

10pdc->FillRect(rcBounds,&brush);

11//设置文字的前景色

12pdc->SetTextColor(TranslateColor(GetForeColor()));

13//显示时钟

14CTime tm=CTime::GetCurrentTime();

15CString str=tm.Format("%H:%M:%S");

16pdc->TextOut(0,0,str);

17 } ———————————————————————————————————————其中,第6行代码调用函数TranslateColor用于将OLE_COLOR颜色类型值转换成COLORREF颜色类型值。第8行代码调用函数SetBkMode用于设置背景模式。再次运行,发现背景是黑色的,什么也看不出来,那是因为我们还没有给它提供背景色和前景色属性。●步骤5:给Time控件添加背景色和前景色属性。

打开Class Wizard,选择Automation选项卡,确定该页面上的Class name下面的下拉组合框中选中的是CTimeCtrl类,因为我们是要给这个类添加。单击对话框上的Add Property按钮,弹出如图14-08所示的Add Property对话框。在这里我们要添加背景色和前景色两个属性,由于系统已经为我们准备好了这两个属性,因此,我们可以在External name后面的下拉组合框中选择到BackColor和ForeColor两个属性,在Implementation组框中选中Stock单选按钮,单击OK按钮就可以了。

这个时候加的属性在Visual Basic环境中测试时可以更改背景色和前景色的颜色值,然而在Visual C++环境中,在ActiveX Control Test Containe测试容器中却找不到这两个属性。当我们在ActiveX Control Test Containe测试容器中鼠标右击插入的控件时,在弹出的快捷方式菜单中选择Properties菜单项,弹出控件的属性页对话框,该对话框有两

图14-08 添加BackColor属性

个页面,第一个页面为Gerneral,上面只显示一个标签,该标签提示用户可以在该对话框上添加控件(Windows普通控件)来处理控件(我们自己创建的ActiveX控件)的属性;第二个页面为Extended,也只显示一个Name属性。现在我们要给控件的属性对话框上添加一个颜色属性页,要实现此功能,就要修改类CTimeCtrl的.cpp文件中的属性页映射宏,在宏BEGIN_PROPPAGEIDS(CTimeCtrl, 1)和宏END_PROPPAGEIDS(CTimeCtrl)之间再添加一个属性页CLSID_CColorPropPage,相应的,BEGIN_PROPPAGEIDS宏的参数中的计数也要加1,结果如下:

BEGIN_PROPPAGEIDS(CTimeCtrl, 2)

PROPPAGEID(CTimePropPage::guid)

PROPPAGEID(CLSID_CColorPropPage)

END_PROPPAGEIDS(CTimeCtrl)

现在再运行,右击控件选择Properties,在控件属性对话框的第二个页面中可以看到我们加的颜色属性,如图14-09所示。在特定名下面的下拉组合框中可以找到我们添加的两个属性:背景色和前景色。这里我们将背景色修改成黄色,将前景色修改成红色。

步骤6:增加一个新的自定义属性,时间间隔(UpdateInterval)。

添加UpdateInterval属性的用意是,可以让用户在Time控件属性对话框的第一个页面上修改时钟显示的时间间隔,因此,需要修改属性框的第一个页面。可以打开工作台的资源面板,在Dialog文件夹下双击ID为IDD_PROPPAGE_TIME的对话框资源,将如图14-10所示的原来的对话框资源修改成如图14-11所示的模样。

图14-10 原有的IDD_PROPPAGE_TIME对话框资源

图14-11 修改后的IDD_PROPPAGE_TIME对话框资源

给Time控件添加一个自定义属性UpdateInterval。同样是打开Class Wizard,选择Automation选项卡,确定该页面上的Class name下面的下拉组合框中选中的是CTimeCtrl 类。单击对话框上的Add Property按钮,然而在External name后面的下拉组合框中不能选择到UpdateInterval属性,因为系统并没有给我们准备,我们需要在该组合框中自己输入属性名UpdateInterval,类型选择long,其他的就按默认的,结果如图14-12所示。

图14-12 添加自定义属性UpdateInterval

单击OK按钮,系统自动为我们提供了一个OnUpdateIntervalChanged事件,并且自动添加了和该属性相关联的数据成员m_updateInterval。当用户修改时间间隔的时候,就会触发系统自动为我们提供的OnUpdateIntervalChanged事件,因此,我们要改变时钟间隔,就可以在函数OnUpdateIntervalChanged中添加如下代码:

void CTimeCtrl::OnUpdateIntervalChanged()

{

// TODO: Add notification handler code

//解决输入值不合要求的问题

if(m_updateInterval<1000||m_updateInterval>5000)

m_updateInterval=1000;

//解决输入值不是整数的问题

m_updateInterval=m_updateInterval/1000*1000;

KillTimer(1);

SetTimer(1,m_updateInterval,NULL);

SetModifiedFlag();

}

现在还要给编辑框控件添加一个数据成员与刚刚建立的属性相关联。打开Class Wizard 的Member Variables页面,确定该页面上的Class name下面的下拉组合框中选中的是CTimePropPage类。给对话框上的编辑框控件(IDC_EDIT1)添加一个相关联的数据成员m_updateInterval,类型为long,最下面的Optional property name下面的下拉组合框中输入与该数据成员相关联的属性UpdateInterval。

步骤7:给UpdateInterval属性创建持久性存储。

我们不难发现,在修改颜色之后,再次重新启动工程时,颜色值还会保留上一次设置的

结果,那是因为,我们添加的背景色和前景色这两个系统提供的属性,系统已经为它们建立了持久性存储;然而当我们修改了时间间隔后,在下一次启动时并不保留上一次的值,因为我们自己添加的UpdateInterval属性没有持久性存储。现在,我们要给UpdateInterval 属性添加持久性存储,在CTimeCtrl::DoPropExchange函数中添加如下代码:void CTimeCtrl::DoPropExchange(CPropExchange* pPX)

{

ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));

COleControl::DoPropExchange(pPX);

// TODO: Call PX_ functions for each persistent custom property.

PX_Long(pPX,"UpdateInterval",m_updateInterval,1000);

}

其中函数PX_Long用来实现持久性存储,它的四个参数的意义从头到尾依次为:pPX,属性名字,设定值,缺省值。这里用的设定值m_updateInterval即是用户在编辑框中输入的值。最后还要修改CTimeCtrl::OnCreate()函数中创建计时器的语句,将代码SetTimer(1,1000,NULL);改为SetTimer(1,m_updateInterval,NULL);就可以了。运行测试,打开ActiveX Control Test Containe测试容器,插入Time Control,右击该控件选择Properties,可以看到空间属性对话框的Gerneral页面上显示了初始的时间间隔1000,并且用户可以修改此时间间隔,如图14-13所示。

图14-13 可以修改时间间隔属性

步骤8:给控件添加一个hello方法。

打开Class Wizard,选择Automation选项卡,确定该页面上的Class name下面的下拉组合框中选中的是CTimeCtrl类,因为我们是要给这个类添加。单击对话框上的Add Method按钮,弹出如图14-14所示的Add Method对话框。在这里我们要添加hello方法,在External name下面的下拉列表框中输入外部名称hello,由于我们定义的该方法不存在返回值,因此在Return type下面的下拉列表框中选择void。单击OK按钮,在工作台的CTimeCtrl类的下面多了一个函数hello(),在该函数中添加MessageBox("Hello World!"); 语句,下面我们在Visual Basic环境中测试一下,看看调用该控件的hello方法的结果。

启动Visual Basic,新建一个项目,右击Visual Basic的控件工具栏,如图14-15所示,选择Components菜单项,弹出如图14-16所示的Components对话框,在该对话框的Controls页面的列表框中找到EX14_00 ActiveX Control module,注意不是添加Time,您在这里是找不到Time Control的,这里是以VC的工程名来标识的。单击确定按钮,可以看

到控件加载到了Visual Basic的控件工具栏中,显示为紫红色的OCX的图标。现在我们在Visual Basic的窗体上添加这个ActiveX控件,注意添加到VB环境中的此控件的名称(Name)属性为Time1;然后再在窗体上添加一个按钮控件,在此按钮控件的Click事件中,调用ActiveX控件Time1的hello方法,如图14-17所示,运行VB程序,单击窗体上的按钮,会弹出提示"Hello World!"的消息框,如图14-18所示。

图14-14 添加hello方法

图14-15 在VB环境加载Time控件

图14-16 添加ActiveX控件

图14-17 在按钮的click事件中调用时钟控件的hello方法

图14-18 调用时钟控件的hello方法的运行结果

步骤9:最后,我们给这个时钟控件添加一个NewMinute事件。

我们设计的目的是,当时钟过去一分钟时就会触发NewMinnute事件,而触发该事件的结果是,弹出一个消息框提示“过了一分钟!”。

打开Class Wizard,选择ActiveX Events选项卡,确定该页面上的Class name下面的下拉组合框中选中的是CTimeCtrl类,因为我们是要给这个类添加。单击对话框上的Add Event按钮,弹出Add Event对话框,在这里我们要添加NewMinute事件。在External name 下面的下拉组合框中输入外部名称NewMinute,这时系统会自动给我们添加一个内部名称FireNewMinute,如图14-19所示。

图14-19 添加NewMinute事件

接下来的任务就是判断时钟是否过了一分钟。因为我们在OnTimer函数中调用了InvalidateControl();语句,即每过一秒(或用户修改后的时间间隔)就会触发控件的OnDraw函数,所以,我们可以在OnDraw函数中判断是否过了一分钟,如下:void CTimeCtrl::OnDraw(

CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) {

// TODO: Replace the following code with your own drawing code.

//定义画刷

CBrush brush(TranslateColor(GetBackColor()));

//将时钟背景改为透明模式

pdc->SetBkMode(TRANSPARENT);

//定义画刷的矩形范围,rcBounds值是OnDraw函数中的参数,由系统传来

pdc->FillRect(rcBounds,&brush);

//设置文字的前景色

pdc->SetTextColor(TranslateColor(GetForeColor()));

//显示时钟

CTime tm=CTime::GetCurrentTime();

//判断是否过了一分钟

if(tm.GetSecond()==0)

{

FireNewMinute(); //触发NewMinute事件

}

CString str=tm.Format("%H:%M:%S");

pdc->TextOut(0,0,str);

}

再在Visual Basic环境中测试。我们可以在Visual Basic的代码编辑环境中找到Time1的NewMinute事件,如图14-20所示。我们在NewMinute事件中添加msgbox “过了一分钟!”代码,然后运行VB程序,当时钟过去一分钟的时候就会弹出消息框提示“过了一分钟!”,如图14-20所示。

图14-20 NewMinute事件运行结果

相关主题
相关文档
最新文档