VC随笔——ActiveX控件

 

VC   2006-10-10 19:39

ActiveX、OLE和COM:

COM(Component Object Model)即组件对象模型是用来解决Windows程序模块之间相互通信的标准方法,是Windows统一的、可扩充的、面向对象的通信协议。COM是一种协议,建立了一个软件模块同另一个软件模块之间的连接,然后将其描述出来。当这种连接建立起来后,两个软件模块之间就可以通过一个称为“接口”的机制来进行通信。

OLE(Object Linking & Embedded)是指对象的链接与嵌入技术。是可嵌入的组件对象模型(COM),它是作为一个进程中的服务器的动态链接库来实线的。(可以将被使用的控件称为服务器,而使用控件的应用程序就是客户程序或者容器程序。)

虽然OLE控件是通过DLL来实现的,但不仅止于此。OLE控件还是一个独立的对象,它可以激起和响应事件、处理消息,它具有唯一的属性,并且它有多线程能力。

OLE控件不能独立存在,需要嵌入到容器中去。

ActiveX控件是在其他应用程序中可以使用的,而且与应用程序无关的小型动态链接库,是OLE控件的子集。能够用于Internet应用程序,当然也可以运行在非Internet应用程序中。

和普通的Windows控件一样,ActiveX控件也是一个子窗口,通常是对话框的子窗口。包含ActiveX控件的窗口称为包容器。

(1)如果要在对话框中加入一个ActiveX控件,和加入一个普通的Windows控件一样,只要在对话框编辑器中,将ActiveX控件放在适当的位置,并在资源模板中表示该ActiveX控件即可。

(2)如果要在程序中动态地建立ActiveX控件,则可以调用相应类的Create成员函数。

ActiveX控件不像普通的控件那样,发送以WM_打头的通知消息给它的包容器窗口,而是“激发事件”。

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

属性、方法和事件:

ActiveX控件有三个重要的属性集:属性(Property)、方法(Method)和事件(Event)。作个简单的类比,属性好比成员变量;方法就是成员函数;而事件则允许控件向容器应用程序发送相应的消息。

属性是ActiveX控件的特性或特征,用户可以访问或设置这些属性。用户可以定制属性或使用库存属性。ActiveX控件的10个库存属性:Appearance、BackColor、BorderStyle、Caption、Enabled、Font、ForeColor、hWnd、ReadyState。

方法是控件访问其本身功能的函数。能够提供访问ActiveX控件的属性和数据的访问函数。方法可以是库存的也可以是定制的。库存方法可以访问库存属性(颜色、字体等),定制方法可以访问定制属性。对应属性的库存方法分为Get方法和Set方法,如shor GetAppearance()、void SetAppearance(short sApear)等。MFC提供了两个库存方法,Doclick方法和Refresh方法。使用Doclick方法可以向容器程序激起一个鼠标敲击事件,使用Refresh方法可以使容器更新控件的外观。

事件是控件在响应外部作用时由控件触发的消息。控件利用事件与控件的容器应用程序进行通信。这种通信只能实现单一计算机的进程之间及进程内部的通信。通过IDispatch接口,控件可以向容器发送消息,容器也可以向控件发送消息。MFC也提供了一些库存的事件:Click、DblClick、Error、KeyDown、KeyPress、KeyUp、MouseDown、MouseMove、MouseUp。相应的驱动事件的函数为void FireClick()等。

组件和控件:

组件是具有特定功能的程序模块,通常是符合一定规范的类,用不同语言开发的组件可相互通信。

控件可以看成是有形的组件,除属性和方法外,通常还有相应的事件。

二者都是能完成一定功能的实体,区别在于控件有一定的形状,一般还有响应事件;组件一般没有形状和事件。

使用ActiveX控件:

1、插入ActiveX控件

(1)创建使用控件的程序

创建一个名为Time的基于对话框的工程,确保在第2步中勾选了ActiveX Controls复选框(系统默认设置)。修改对话框的标题为“测试ActiveX控件”。

(2)添加日历控件

1)单击Project|Add to Project|Components and Controls菜单项,双击Registered ActiveX Controls目录,插入Calendar Control 8.0的日历控件。

2)使用默认设置。此时,在对话框编辑窗口右边的控件面板上,在最下面多了一个日历控件的图标,同时在Class View中新添加了两个类CCalendar和COleFont。

3)在对话框模板上添加日历控件。在日历控件外添加一个分组框“日期”,下方添加一个只读编辑框。

2、使用属性、方法和事件

(1)修改控件的属性

在日历控件的属性对话框中修改日历控件的背景颜色属性为“桌面”

(2)添加事件处理函数

ActiveX控件不像普通的控件那样,发送以WM_打头的通知消息给它的包容器窗口,而是“激发事件”。但是它们的处理方式却是相似的,都可以使用ClassWizard来为事件(或者消息)添加处理函数。

打开ClassWizard对话框,单击Message Maps选项卡,在Class name中选择对话框类CTimeDlg,在object IDs列表中选择日历控件IDC_CALENDAR1,双击Click(单击)事件,添加处理函数OnClickCalendar1。

注意:不是“消息处理函数”

(3)使用控件方法

当日历控件被单击时,将调用控件的方法GetYear、GetMonth、GetDay获取当前的年份、月份以及日期。然后将获得的日期输出到只读编辑框中。

1)为日历控件和编辑框添加对应的成员变量。

使用ClassWizard为日历控件添加一个CCalendar类型的控件成员m_Calendar;为编辑框添加一个CString类型的数据成员m_sDate。

2)修改CTimeDlg类中的OnClickCalendar1函数如下:

void CTimeDlg::OnClickCalendar1()
{
 // TODO: Add your control notification handler code here
 //使用日历控件的方法获取日期
 int year = m_Calendar.GetYear();
 int month = m_Calendar.GetMonth();
 int day = m_Calendar.GetDay();

 //将获得的日期写入于编辑框对应的成员变量中
 m_sDate.Format("%4d年%2d月%2d日", year, month, day);

 //将日期显示在编辑框中
 UpdateData(FALSE);
}

3)此时,当对话框刚显示出来时,编辑框中没有显示任何文本(因为对应变量的初始值为空)。可以在CTimeDlg的OnInitDialog函数中添加类似的代码,使编辑框初始便显示日期。同时对日历控件的显示进行初始化。OnInitDialog函数的部分代码如下:

BOOL CTimeDlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 ...

 // TODO: Add extra initialization here
 CTime time;
 time = CTime::GetCurrentTime(); //获取系统时间

 //初始化日历控件的显示
 m_Calendar.SetYear(time.GetYear());
 m_Calendar.SetMonth(time.GetMonth());
 m_Calendar.SetDay(time.GetDay());

 //初始化编辑控件成员变量的数值
 m_sDate.Format("%4d年%2d月%2d日", time.GetYear(),
       time.GetMonth(), time.GetDay());
 //将日期显示在编辑框中
 UpdateData(FALSE);

 return TRUE;  // return TRUE  unless you set the focus to a control
}

编写ActiveX控件:

编写控件可以分为两种:

(1)一是从MFC提供的控件类派生一个新类,通过合理地设计派生类,可以修改控件的行为和属性以达到用户的要求,但此类控件使用范围很小。

(2)二是编写一个ActiveX控件,以后可以在不同的应用程序中重复使用。

1、创建ActiveX控件框架:

(1)创建ActiveX控件工程

使用MFC ActiveX ControlWizard创建一个名为MyTime的ActiveX控件工程,使用默认设置。

(2)MyTime控件的文件构成

查看MyTime工程的Class View页面,其中:

_DMyTime:一个dispinterface类型的结构,用来包含控件的属性和方法。

_DMyTimeEvents:也是一个dispinterface类型的结构,用来包含控件的事件。

CMyTimeApp:此类派生自COleControlModule,用于初始化控件。可以在该类的InitInstance函数中添加相应的初始化代码;在ExitInstance函数中添加清除代码。

CMyTimeCtrl:此类派生自COleControl类,主要处理控件的显示以及对消息的响应等,后面的大部分工作就是对这个类进行编程。

CMyTimePropPage:此类派生自COlePropertyPage类,这个类描述了控件属性对话框中的名为Control的选项卡。

全局对象DllRegisterServer函数用于注册控件,DllUnregisterServer用于移出注册。

注意:使用ControlWizard产生的ActiveX控件都派生自COleControl类。

(3)测试ActiveX控件

单击Tools|ActiveX Control Test Container菜单项,使用Visual C++6.0提供的ActiveX控件测试工具来测试MyTime控件。单击测试工具程序的Edit|Insert New Control菜单项,在Insert Control对话框中选择MyTime Control控件。

2、修改ActiveX控件的显示:

首先获取系统当前时间,然后将时间转换成文本在控件中输出。同时,还必须根据时、分、秒的数值将时钟画出来。

(1)显示时钟

1)修改CMyTimeCtrl类的构造函数CMyTimeCtrl如下:

CMyTimeCtrl::CMyTimeCtrl()
{
 InitializeIIDs(&IID_DMyTime, &IID_DMyTimeEvents);

 // TODO: Initialize your control's instance data here.
 SetInitialSize(200, 230); //设置控件初始尺寸大小
}

2)修改CMyTimeCtrl类的OnDraw函数如下:

void CMyTimeCtrl::OnDraw(
   CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
 // TODO: Replace the following code with your own drawing code.
 pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
// pdc->Ellipse(rcBounds);
 pdc->SetBkMode(TRANSPARENT); //设置背景透明

 CTime time;
 time = CTime::GetCurrentTime(); //获取系统时间

 double pi = 3.14159265; //圆周率
 int cx = rcBounds.left + 100; //时钟的中心位置x坐标
 int cy = rcBounds.top + 100; //时钟的中心位置y坐标

 //使用循环画出时钟盘面
 for(int i=0; i<60; i++)
 {
  int x = cx + 80*cos(i*pi/30) +0.5;
  int y = cy + 80*sin(i*pi/30) +0.5;

  if(i%5 == 0) pdc->Ellipse(x-3, y-3, x+3, y+3); //大刻度
  else   pdc->Ellipse(x-1, y-1, x+1, y+1); //小刻度
 }

 CString str = time.Format("%H:%M:%S"); //将时间写入字符串

 //输出字符串,在时钟下面以数字方式显示时间
 pdc->TextOut(rcBounds.left+70, rcBounds.top+200, str);

 ///
 // 下面将使用三种不同粗细的画笔来画出时钟的时针、分针和秒针
 ///
 CPen pen1(PS_SOLID, 4, RGB(0,0,0)); //时针画笔
 CPen pen2(PS_SOLID, 2, RGB(0,0,0)); //分针画笔
 CPen pen3(PS_SOLID, 1, RGB(0,0,0)); //秒针画笔

 //根据当前时间计算时针的终点位置(x1,y1)
 int x1 = cx + 40*cos((time.GetHour()-3)*pi/6 +
  (time.GetMinute()/12)*pi/30) + 0.5;
 int y1 = cx + 40*sin((time.GetHour()-3)*pi/6 +
  (time.GetMinute()/12)*pi/30) + 0.5;
 //根据当前时间计算分针的终点位置(x2,y2)
 int x2 = cx + 60*cos((time.GetMinute()-15)*pi/30) + 0.5;
 int y2 = cx + 60*sin((time.GetMinute()-15)*pi/30) + 0.5;
 //根据当前时间计算秒针的终点位置(x3,y3)
 int x3 = cx + 70*cos((time.GetSecond()-15)*pi/30) + 0.5;
 int y3 = cx + 70*sin((time.GetSecond()-15)*pi/30) + 0.5;

 CPen * pOldPen = pdc->SelectObject(&pen1);
 pdc->MoveTo(cx, cy); //画出时针
 pdc->LineTo(x1, y1);

 pdc->SelectObject(&pen2);
 pdc->MoveTo(cx, cy); //画出分针
 pdc->LineTo(x2, y2);

 pdc->SelectObject(&pen3);
 pdc->MoveTo(cx, cy); //画出秒针
 pdc->LineTo(x3, y3);

 pdc->SelectObject(pOldPen); //落选画笔
}

3)由于使用了数学函数sin和cos,因此在MyTimeCtl.cpp文件中包含math.h:

#include "math.h"

(2)增加计时器

接下来,要让时钟能够动起来。类似在状态栏上显示时间一样,将要为MyTime添加WM_TIMER消息处理,并设置定时器。

1)使用ClassWizard为CMyTimeCtrl类添加三个消息处理,WM_CREATE消息处理函数Oncreate,WM_TIMER消息处理函数OnTimer,WM_CLOSE消息处理函数OnClose。

2)修改OnCreate函数如下:

int CMyTimeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (COleControl::OnCreate(lpCreateStruct) == -1)
  return -1;

 // TODO: Add your specialized creation code here
 SetTimer(1, 1000, NULL); //设置计时器

 return 0;
}

3)修改OnTimer函数如下:

void CMyTimeCtrl::OnTimer(UINT nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
 InvalidateControl(); //重画控件,相当于调用OnDraw函数

 COleControl::OnTimer(nIDEvent);
}

4)修改OnClose函数如下:

void CMyTimeCtrl::OnClose()
{
 // TODO: Add your message handler code here and/or call default
 KillTimer(1); //释放计时器

 CWnd::OnClose();
}

(3)修改控件示意图标

打开MyTime控件工程的资源,修改名为IDB_MYTIME的位图资源。

编译MyTime控件工程,将MyTime控件插入到Time工程。修改Time工程的IDD_TIME_DIALOG对话框模板,插入一个MyTime控件和一个分组框。

注意:(1)此时,查看MyTime控件的属性,会发现Control和All属性对话框都是空白的,因为此时还没有为MyTime控件添加任何属性。

(2)此时,如果使用ClassWizard查看MyTime控件所能产生的事件时,会发现是空的,因为此时还没有为控件添加事件。

3、添加属性:

4、使用库存属性的对应方法:

5、添加属性页:

6、添加事件:

步骤总结:

1、使用MFC ActiveX Control Wizard创建控件工程框架

2、定制控件的界面和图标

3、为控件添加属性、事件和方法并进行相应的处理




引文来源  VC随笔——ActiveX控件 - vivianas的日志 - 网易博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值