1,ActiveX控件理解:
ActiveX控件是一个极小的服务器应用程序,他不能独立运行,必须嵌入到某个容器程序中,与容器一起运行,如VB,VC,也有点象插件,组件的形式,在VC中,可以把ActiveX控件认为是资源里的,可以拖动到对话框上的小控件,这里就是说明怎么样制作这样一个VC的小控件。(参考孙鑫VC++深入详解)。
2,生成一个小时钟控件:可以显示当前时间 :Clock.ocx
用VC6,通过MFC ActiveXContolWizad可以创建一个工程,一个工程可以包含多个控件,这里选默认1个。
通过向导可以不写任何代码生成三个类:CClockApp(相当于应用程序类),CClockCtrl(相当于视类),CClockProPage(控件的属性页类)。还生成两个接口:_DCLOCK, _DCLOCKEVENTS.(说明一下:控件主要包括属性,方法和事件机制)。通过_DCLOCK得到属性和方法,通过_DCLOCKEVENTS得到控件的事件,主要是控件发出事件通知容器程序,容器可以对事件作出反应,也可以不作出反应)。
VC编译成功时会出现两行:Registering ActiveX Control…
RegSvr32:DllRegisterServerin.\Debug\Clock.ocx succeeded.
表示编译成功,且已经注册成功。这时这个控件就可以再别的程序如VB里调用了,若要取消注册,可以:开始菜单->运行里输入:regsvr/u 控件的绝对路径。
2.1:时钟控件的实现:
上面生成的控件没有时钟的功能,只是一个椭圆,因为在CClockCtrl里的OnDraw()里有这样几行代码:// pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
// pdc->Ellipse(rcBounds);
注释起来:加入自己的代码:
CBrushbrush(TranslateColor(GetBackColor()));//…………1
pdc->FillRect(rcBounds,&brush);
pdc->SetBkMode(TRANSPARENT);
pdc->SetTextColor(TranslateColor(GetForeColor()));
CTimetime=CTime::GetCurrentTime();
if(0==time.GetSecond())
{
FireNewMinute();
}
CStringstr=time.Format("%H:%M:%S");
pdc->TextOut(0,0,str);
意思是:用控件的背景颜色填充矩形,然后得到当前时间,用控件的前景颜色填充文字,注意使用pdc->SetBkMode(TRANSPARENT);使的文字的背景透明,至于FireNewMinute();
是后面设置的一个事件驱动:当秒=0时,控件会像他的容器发出一个事件,容器是否处理他就要看的具体要求了。得到背景色和前景色是后面对控件添加的属性。不然也不会有这两项。
这样的控件的时间还是静止的,要让他动起来,需要每个1秒钟调用一个OnDraw()函数,自然后想到设置一个定时器。在那里设置呢?
要在程序一运行起来就要动起来,自然可以再OnCreate()里定义,恰好CClockCtrl这个跟视类相当的类里有一个OnCreate(),在里面添加:
SetTimer(1,m_interval,NULL); // m_interval为定时器时间,我们完全可以不让他1种走一次,自己设定他。
当然这样就要在OnTimer()里来调用刷新了:
if(AmbientUserMode()) ///这句可以不要,加上他只是说明控件在什么模式下才刷新///OnDraw().这里是在控件属性运行状态时才刷新。
InvalidateControl();//也可以直接调用另一个函数Invalidate()
这样一个可以动的时钟控件就出来了。设定好m_interval=1000,就是时钟了。
2.2 时钟控件的完善:
在VB里控件面板里总会有前景色和背景色的选项,我们希望这个时钟控件也可以达到那种效果。
在VC通过Class Wizard来完成,选择Automation->Add Property可以选择常规属性BackColor ForeColor等。选好后,可以再_DCClock里多了:
[id(DISPID_BACKCOLOR), bindable,requestedit] OLE_COLOR BackColor;
[id(DISPID_FORECOLOR), bindable, requestedit]OLE_COLOR ForeColor;
这就是我们可以再上面的1处添加那两句代码的原因了。
然后可以为这个控件添加属性页,
在CClockCtr的源文件里,可以看到下面,意思说这个控件有一个属性页,且标示符为guid.要添加另外一个属性页,就要改1为2,相应加入颜色属性页的标识符。
BEGIN_PROPPAGEIDS(CClockCtrl,1)
PROPPAGEID(CClockPropPage::guid)
END_PROPPAGEIDS(CClockCtrl)
改为:
BEGIN_PROPPAGEIDS(CClockCtrl,2)
PROPPAGEID(CClockPropPage::guid)
PROPPAGEID(CLSID_CColorPropPage)//颜色属性页的guid为//CLSID_CColorPropPage
END_PROPPAGEIDS(CClockCtrl)
这样控件就有了个颜色属性页。
2.3:自定义属性 时间间隔m_interval
要时钟控件多久更新一次,我们通过属性页给定一个值来设定。
同样通过向导,增加属性,选择Member variable 增加一个变量,这时程序自动增加一个函数:OnIntervalChanged(),在控件外部修改这个m_interval时,此函数被调用。
在此函数里添加:
if(m_interval<0|| m_interval>6000)
{
m_interval=1000;
}
else
{
m_interval=m_interval/1000*1000;
KillTimer(1);
SetTimer(1,m_interval,NULL);
BoundPropertyChanged(0x1);
}
SetModifiedFlag();
意思:首先对输入的值进行判断,过大过小都设置为1000,其他的按取整计算。
问题:m_interval初值怎么办?第一次启动他的间隔是多少了?
在CClockProPage类对应的属性也上上添加一个文本框,并且关联一个变量:m_updateInterval,这么做得同时,向导会提示我们是否为这个变量关联一个属性,这里选择关联上面的时间间隔属性,Interval;这样就为这个属性添加了一个属性页了。在CClockPropPage的DoDataExchange(CDataExchange* pDX)函数里就会自动多加几行:
DDP_Text(pDX, IDC_EDIT_INTERVAL,m_updateInterval, _T("Interval") );
DDX_Text(pDX, IDC_EDIT_INTERVAL,m_updateInterval);
文本框初始值为0,当然就解决了上面的问题。你在运行程序时可以设定为别的值,比如说1000。
我们希望这个设置的值一直都能保存下去,下次启动时不要重新设置怎么办?
2.4属性的持久性:
只需在CClockCtrl的DoPropExchange(CPropExchange* pPX)里加入
PX_Short(pPX,"Interval",m_interval,1000);
m_interval就有了持久性了,后面那个1000是缺省值。也就是当没有为文本框制定值时,他默认为1000而不是0了。
还有一个问题,在VB里调试这个时钟程序时发现,他自身的属性页与Vb的属性面板对应不起来,比如吧时间间隔调到2000,但是Vb的属性框里没有变化。解决:
在CClockCtrl的OnIntervalChanged() 加上BoundPropertyChanged(0x1);通知容器作出反应。
2.4 方法:
跟添加属性差不多可以添加方法。添加方法跟VC里添加成员函数相对应,添加属性跟天剑成员变量相对应。
2.5:事件:
标准事件:
通过向导添加事件,在接口-DCCLOCKEVENT中会多了点击事件,在Vb里可以调用窗口过程对改事件作出反应或者不反应。
自定义事件:
当秒钟=0时,我们增加一个事件,FireNewMinute();同理在vb中可以对该事件作出或者不作出反应。
以上控件就生成好了,如要把它放到VC里,就像普通的加入Vc组件一样加入。然后调用它的函数,变量。添加事件可以鼠标又击这个控件选择Events.添加。该栏就会显示该控件所有的事件。