孙鑫18课Active控件.docx
《孙鑫18课Active控件.docx》由会员分享,可在线阅读,更多相关《孙鑫18课Active控件.docx(14页珍藏版)》请在冰豆网上搜索。
孙鑫18课Active控件
容器和服务器程序
⏹容器应用程序是可以嵌入或链接对象的应用程序。
Word就是容器应用程序。
⏹服务器应用程序是创建对象并且当对象被双击时,可以被启动的应用程序。
Excel就是服务器应用程序。
ActiveX控件的四种属性
⏹Stock:
为每个控件提供的标准属性,如字体或颜色。
⏹Ambient:
围绕控件的环境属性——已被置入容器的属性。
这些属性不能被更改,但控件可以使用它们调整自己的属性。
⏹Extended:
这些是由容器处理的属性,一般包括大小和在屏幕上的位置。
⏹Custom:
由控件开发者添加的属性。
切换到VB的运行环境中。
VB做为ACTIVEX控件测试容器;
VB中加载ACTIVEX控件:
选择工程下面的组件:
选择MICROSOFTWINSOCKCONTROL6.0
(。
OCX是ACTIVEX控件的后缀名,但是ACTIVEX控件的后缀名不一定是.OCX,也可以是其它的名字,比如。
DLL),选上后,点确定。
选择VIEW下的OBJECTBROWSER。
在所有库的下拉列表中,选择MSWINSOCKLIB。
可以看到WINSOCK控件出来了。
其中,绿色控件表示方法。
小手表示控件属性。
闪电表,示事件。
一个典型ACTIVEX控件会有这三个属性。
ACTIVEX控件好处:
把常用的功能封装到ACTIVEX控件中,提供给程序开发使用。
新建一个工程,选择MFC的MFCACTIVEXCONTROLWIZARD,名字是TEST。
(开发一个时钟控件)。
保持缺省,完成。
平放的小勺是接口。
外部的函数通过接口去访问控件的属性和方法。
在接口中定义的所有函数都是纯虚函数。
通过接口调用的函数是调用CTestCtrl中真正实现的函数。
编译一个,会在DEBUG目录下有一个TEST.OCX,这就是控件,要用的话,把它放到要用的目录下面。
不能!
运行程序,因为它必须要有一个容器。
选择ACTIVEXCONTROLTESTCONTAINER。
选择EDIT下面的INSERTNEWCONTROL…….出现下面的图,选择我们的TESTCONTROL。
(VC编译环境中)
下面是VB环境中:
ACTIVEX要先注册,再能使用。
要想删除ACTIVEX的注册信息:
运行regsvr32/u(/u表示反注册,然后将TEST.OCX拉到regsvr32/u后面),弹出:
这时候就找不到TESTACTIVEX控件了。
要想再注册,用上面同样的方法,但是/u要取消。
这时弹出的消息如下:
这时再找,就可以找到TEST.OCX了。
在VC中的TOOLS菜单下的REGISTERCONTROL也可以达到上面的效果。
控件使用之间,都要注册。
在控件上面输出当前时间。
代码如下:
voidCTestCtrl:
:
OnDraw(
CDC*pdc,constCRect&rcBounds,constCRect&rcInvalid)
{
//TODO:
Replacethefollowingcodewithyourowndrawingcode.
CTimet=CTime:
:
GetCurrentTime();
CStringstrtime=t.Format("%H:
%M:
%S");
pdc->TextOut(0,0,strtime);
//系统下面自动加的这两句代码是为了填充背景和画椭圆的。
//pdc->FillRect(rcBounds,CBrush:
:
FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
//pdc->Ellipse(rcBounds);
}
编译的时候要先将测试中的TEST控件删除。
上面这段代码的时间是静止的,不会动,下面创建一个动态的时钟。
intCTestCtrl:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(COleControl:
:
OnCreate(lpCreateStruct)==-1)
return-1;
//TODO:
Addyourspecializedcreationcodehere
SetTimer(1,1000,NULL);
return0;
}
voidCTestCtrl:
:
OnTimer(UINTnIDEvent)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
Invalidate();
下面这句也可以:
InvalidateControl();
二者等效。
COleControl:
:
OnTimer(nIDEvent);
}
这时时间动起来了。
下面为控件添加设置前景色和背景色。
然后再增加前景色。
voidCTestCtrl:
:
OnDraw(
CDC*pdc,constCRect&rcBounds,constCRect&rcInvalid)
{
//TODO:
Replacethefollowingcodewithyourowndrawingcode.
COLORREFbkcolor=TranslateColor(GetBackColor());
CBrushbrush(bkcolor);
pdc->FillRect(rcBounds,&brush);
COLORREFtxcolor=TranslateColor(GetForeColor());
pdc->SetTextColor(txcolor);
pdc->SetBkMode(TRANSPARENT);
CTimet=CTime:
:
GetCurrentTime();
CStringstrtime=t.Format("%H:
%M:
%S");
pdc->TextOut(0,0,strtime);
//系统下面自动加的这两句代码是为了填充背景和画椭圆的。
//pdc->FillRect(rcBounds,CBrush:
:
FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
//pdc->Ellipse(rcBounds);
}
通常一个ACTIVEX控件会提供自己属性页。
在TestCtl.cpp中:
BEGIN_PROPPAGEIDS(CTestCtrl,2)
PROPPAGEID(CTestPropPage:
:
guid)//guid表示全局唯一标识符。
PROPPAGEID(CLSID_CColorPropPage)//颜色属性页
END_PROPPAGEIDS(CTestCtrl)
这时属性页就出现了。
下面给控件添加一个自定义的属性:
增加一个时间间隔的属性。
voidCTestCtrl:
:
OnIntervalChanged()
{
//TODO:
Addnotificationhandlercode
if(m_interval<0||m_interval>6000)
{
m_interval=1000;
}
else
{
m_interval=m_interval/1000*1000;//将用户输入取整,2345-》2000.
KillTimer
(1);//销毁先前的定时器
SetTimer(1,m_interval,NULL);//设置新的定时器
}
SetModifiedFlag();
}
接下来将自定义的属性在属性表单中进行设置。
在IDD_PROPPAGE_TEST中:
并为EDIT它关联一个short型的m_timeinterval;
下面的interval是外部名称。
下面是运行结果:
下面给控件添加方法:
voidCTestCtrl:
:
Hello()
{
//TODO:
Addyourdispatchhandlercodehere
MessageBox("helloworld!
");
}
接下来给控件添加一个事件:
[uuid(00E87A5D-986C-4FF9-BE79-C3F0F96AA13C),
helpstring("TestControl"),control]
coclassTest
{
[default]dispinterface_DTest;
[default,source]dispinterface_DTestEvents;//表示控件用这个接口来发送通知事件,这个接口不是控件本身实现的接口。
};//source表示_DTestEvents是一个源接口,是由窗口来实现的。
这时测试:
下面增加一个自定义的事件:
在_DTestEvents上右击弹出下面对话框:
在voidCTestCtrl:
:
OnDraw中添加:
if(0==t.GetSecond())
{
FireNewminute();
}
测试结果:
新的一分钟到达时,事件发送了。
当添加自定义的事件时,一定要在事件发生时,去发出事件通知。
标准事件时,MFC自动帮我们实现。
将文件设置前景色,背景色,时间间隔,然后保存,再次打开,发现时间间隔没有保存下来(前景色和背景色都保持下来),说明时间间隔没有持久性。
voidCTestCtrl:
:
DoPropExchange(CPropExchange*pPX)//此函数是做持久性的。
{
ExchangeVersion(pPX,MAKELONG(_wVerMinor,_wVerMajor));
COleControl:
:
DoPropExchange(pPX);
//TODO:
CallPX_functionsforeachpersistentcustomproperty.
PX_Short(pPX,"interval",m_interval,1000);
}
intCTestCtrl:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(COleControl:
:
OnCreate(lpCreateStruct)==-1)
return-1;
//TODO:
Addyourspecializedcreationcodehere
SetTimer(1,m_interval,NULL);
return0;
}
接下来再看一个问题:
在VB中做测试,当通过属性页改变时间间隔时,VB窗口中的属性时间间隔并没有随之改变。
这主要是因为自定义的属性在发生改变时,没有通知容器,让容器调整。
由上图可以看出,间隔的属性调度ID为1.
voidCTestCtrl:
:
OnIntervalChanged()
{
//TODO:
Addnotificationhandlercode
if(m_interval<0||m_interval>6000)
{
m_interval=1000;
}
else
{
m_interval=m_interval/1000*1000;//将用户输入取整,2345-》2000.
KillTimer
(1);//销毁先前的定时器
SetTimer(1,m_interval,NULL);//设置新的定时器
BoundPropertyChanged
(1);
}
SetModifiedFlag();
}
在VB中,可以在设计时,也可以在运行时改变控件的属性。
在设计时,时间值不动,在运行时,时间值才改变。
容器知道自己是在设计是还是在运行时。
voidCTestCtrl:
:
OnTimer(UINTnIDEvent)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
if(AmbientUserMode())//运行时
{
InvalidateControl();
}
COleControl:
:
OnTimer(nIDEvent);
}
当编写完ACTIVEX后,可以选择
编译,就可以生成一个发行版的OCX控件,在发行模式下进行编译时,VC程序会做一些优化,同时生成的可执行文件比较小。
下面做一个VC的测试程序,用来访问我们做的ACTIVEX控件。
新建一个MFC的对话框程序(TestTest)
在对话框上点击右键,插入ACTIVEX控件,选择我们刚刚建立的TEST控件。
放置一个,然后右击它,可以看到相应的属性。
还可以通过工程下面的添加到工程(组件和控件),选择ACTIVEX
上面都是通过静态增加的,下面动态增加一个。
在对话框上面增加一个按钮,当点击这个按钮的时候,动态的增加一个时钟控件。
为CTestTestDlg增加:
private:
CTestm_clock;
在头文件中:
#include"test.h"
voidCTestTestDlg:
:
OnButton1()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
m_clock.Create("windowname",WS_VISIBLE|WS_CHILD,CRect(0,0,100,70),this,123);
m_clock.Hello();
m_clock.SetBackColor(RGB(255,0,0));
m_clock.SetForeColor(RGB(0,255,0));
m_clock.SetInterval(m_clock.GetInterval()*2);
}
下面是对事件进行响应:
voidCTestTestDlg:
:
OnnewminuteTestctrl3()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
MessageBox("newminute!
");
}
对于一个动态创建的控件,去响应它的事件对象:
在创建的时候,给它分配了一个ID号,根据这个ID号,自己写。
下面是我写的:
由于创建时,控件ID选为123,修改代码如下:
TestTestDlg.h中:
afx_msgvoidOnnewminute123();
在TestTestDlg.cpp中:
BEGIN_EVENTSINK_MAP(CTestTestDlg,CDialog)
//{{AFX_EVENTSINK_MAP(CTestTestDlg)
ON_EVENT(CTestTestDlg,IDC_TESTCTRL3,1/*newminute*/,OnnewminuteTestctrl3,VTS_NONE)
ON_EVENT(CTestTestDlg,123,1/*newminute*/,Onnewminute123,VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
voidCTestTestDlg:
:
Onnewminute123()
{
MessageBox("newminute123!
");
}