ActiveX深入浅出(二)

作者:网络 来源:佚名 更新时间:2008-11-15 10:50:30 点击:
   what an event

   事件是用来通知使用控件的程序员,某件事情发生了,好让程序员可以相应的处理。事件在vb编程中比比皆是,例如,当鼠标点击控件事会发生click事件,文本框内容改变了会发生change事件,等等。但这儿要讲的不同于这些东西,也不同于initproperties, readproperties, writeproperties前面提到过的事件,那些是系统已经定义好了的。我们要做的是定义自己的事件。自定义的事件必须声明在模块的声明部分,然后就能够在任何地方任何时候,只要你觉得应该有事件了,就可以触发它。例如,一个代表眨眼的事件应该这样声明:

   public event blink()

   在括号中,你可以放置任何你想要传递给事件的参数。对于一个click事件,这个参数可能鼠标点击时x和y坐标。而这在理,应为只是眨眼,就用不到额外的参数了。

   触发事件,得使用raiseevent方法。对于我们的眨眼事件,我们把它和一个计时器联系起来,这样它就能够时不时的眨眼了:

   private sub blinker_timer()

   raiseevent blink

   end sub

   就这样,一个事件就完成了,没有任何技巧或者秘密可言。现在留给程序原作的,只要编写相应的事件处理过程就行了,就像下面这样:

   private sub bodycontrol1_blink()

   debug.print "嘻嘻,我又眨眼了!"

   end sub

   到这儿,大部分关于activex控件的基本问题都讲了。后面的将是一些更高级的内容,包括图片和字体属性,“关于”对话框,运行时之读属性等等。在继续之前,再看看前面的内容,好好的在理解一下。好了吗?ok,现在开始更为激动的历程。

   首先,我们先来看看对于属性,还有什么可以挖掘的东西,比如颜色或者图片之类的东西。

   高级属性设计

   色彩值被存贮在长整形变量中,但是如果你只是定义一个长整形变量,显然是不能够得到像vb中所提供的那个颜色选单:

   这看起来很复杂,实际上做起来却一点也不难:所有你要做的只是把属性声明为ole_color类型,就像下面这段代码所作的那样:

   public property get backcolor() as ole_color

   backcolor = usercontrol.backcolor

   end property

   public property let backcolor(byval new_backcolor as ole_color)

   usercontrol.backcolor = new_backcolor

   propertychanged "backcolor"

   end property

   记得前面曾经提过除了let,get,还有第三种属性过程吗?现在揭开迷底:它就是set属性过程,当要给对象变量赋值的时候,是不能用let,而必须用set来代替。这是因为保存在控件内部的对象变量,保存的并不是对象的拷贝,而只是对象的引用,也就是一个内存地址了。为了同一般变量的复制保存区别开来,vb引入了set属性过程。

   或许你可能知道:字体和图片就是保存在对象中的,而且,它们都拥有各自的的对话框来设置相关属性。要用到这些对话框,所有我们要作的就是把图片或者字体申声明为picture或者font对象类型,并且为其设置set属性过程。

   public property get font() as font

   set font = lbltext.font

   end property

   public property set font(byval new_font as font)

   set lbltext.font = new_font

   propertychanged "font"

   end property

   看看上面的代码,你是不是在想:也没有什么很难的啊。确实,就是这样简单啊。下面,我们来看看如何为控键建立只读属性。这也是在控件的设计中用的比较多的一个内容。

   只读属性

   最简单的方法,就是不要在let/set属性过程中加入任何东西。但通常,这并不能满足要求,有时,你可能需要一个运行时只读的属性。所谓运行时——和设计时相对应,是指控件最终在一个开发完成的程序中运行,而设计时指的是控件被使用在开发程序的过程中。

   要实现运行时只读,要用到usercontrol的ambientproperties对象。它提供了很多关于控件容器的属性。中有一个usermode属性,当控件处在运行时状态时,usermode值为真。通过在let/get过程中提供对usermode的检测,就可以很容易的实现运行是只读属性了:

   public property get multiline() as boolean

   multiline = m_multiline

   end property

   public property let multiline(byval new_multiline as boolean)

   if ambient.usermode then

   err.raise 382

   exit sub

   endif

   m_multiline = new_multiline

   propertychanged "multiline"

   end property

   这段代码保护属性只能够在设计时被修改,如果在运行时试图改变它, 就会产生“property is read-only at run-time”错误。

   和ambientproperties对象相近的还有extender对象。对于extender对象,在开始编写控件前有必要好好的了解。extender对象是一个晚期绑定的借口,开发员可以通过它访问由控件容器(而不是控件本身)维护和控制的控件属性。它提供了一些属性,像name,enable,left,top,height,width等等,这些大多出现在一般的控件中,在编写控件属性前,应该看看是否已经存在在extender对象中,一方面可以避免重复工作,另一方面也更有效率。

   但是使用extender对象还存在一些问题:并不是所有的容器都支持访问相同的extender属性。所以选用extender对象是必须十分小心,否这做出的控件只能为特定的容器所使用。但如果你只是为vb开发控件,那就不用有这些顾虑了,尽量的用吧。

   还有一点要注意的是,extender对象不能在usercontrol的initialize事件中访问它,但是可以在initproperties和readproperties事件中使用。

   枚举

   在控件中设置属性时,使用枚举是一种很常见的的方式。它提供了一个下拉列表和若干选项让你选择。这样方便了用户的操作,又不用考虑过多的兼容性和错误处理问题,简化了属性设置,而且更加安全。

   首先,必须建立一个枚举结构,放在声明部分。然后给出一系列的常量和对应的字符串。常量值可以零,或者是任何比它前面一个常量值大的整数。如果没有给出常量,那么vb自动为其赋值,第一个未指定的赋值为零,其它的值为前面一个数加一:

   public enum edirection

   left

   right = 1

   up

   down

   end enum

   要实现枚举属性,必须创建一个带有let和get属性过程的标准属性。这里的技巧是将属性的类型声明为给出的枚举类型:

   public property get direction() as edirection

   direction = m_direction

   end property

   public property let direction(byval new_direction as edirection)

   m_direction = new_direction

   propertychanged "direction"

   end property

   唯一要注意的是,只能够在设计时修改属性列表,而不允许在运行时这么做。其它的,像读,写,保存和检索,都和使用标准属性是一样的。

   这就是所有的技巧了。难以置信的简单,是吗?你的控件是不是看起来更为专业了呢?

   usercontrol对象

   用 visual basic 所创建的 activex 控件总是由 usercontrol 对象加上选中放到 usercontrol 上的任何控件(称为子控件或则组成控件)所组成。就象 visual basic 窗体一样,usercontrol 对象具有代码模块以及可视化的设计器。将组成控件放到 usercontrol 对象的设计器上,就象把控件放到窗体上一

||| 样。 在窗体上放置 activex 控件的实例时,就创建了 usercontrol 对象,以及放在 usercontrol 设计器上的所有子控件的实例。这些对象都被封装在控件中。

   usercontrol 对象有自己的属性、方法和事件。对于一些属性,像borderstyle,backcolor等等,与其自己写代码来实现 backcolor 属性,不如就直接使用usercontrol对象的。这就意味着 activex 控件的 backcolor 属性只需要简单地调用 usercontrol 对象的 backcolor 属性就行了。同样地,也可以在usercontrol 对象现有的 click 事件的基础上设计您的控件的 click 事件。

   事实上在前面的内容中,我们时时都在和这个对象打交道,但是它有一些特别的东西,是应该值的多一些注意的。它的大部分属性应该在控件的设计时来完成设置。在这儿我解释一些比较晦涩难懂得属性的含义,还有一些一望既知,就不多费口舌了。

   alignable属性,当被设置成真的时候,vb将自动为控件添加一个新的属性:align。这样就能够像放置工具条那样安排控件在容器中的位置,而且这还意味着你的控件能够被放置在mdi程序中。

   cangetfocus属性,能够决定用户控件是否能够在运行时获得焦点。当要创建一个图形控件,或者像timer那样在运行是不可见的控件时,就要设置这个值为false。要注意的是:只要控件至少包含一个设置为能够接收焦点的子控件,cangetfocus 属性就不能设置为 false。如果 cangetfocus 设置为 false,则其所有的子控件都不能设置为接收焦点。

   controlcontainer属性定义一个控件是否能够像frames或者pictureboxes控件那样作为控件容器包含其它的控件。

   defaultcancel 属性可以为控件添加default和 cancel属性。在添加 default 和 cancel 属性后,控件就可充当标准命令按钮。也就是说当default被设为ture后,按下回车键会触发控件的click事件,而当cancel属性被设为ture时,esc键按下也会触发click事件。

   你可以通过检查ambientproperties对象的displayasdefault属性来知道控件是不是缺省控件。

   invisibleatruntime能够让你建立像timer之类的控件,在运行的时候是不可见的。

   最后,toolboxbitmap 属性用来指定放在vb工具箱上的图标的。微软建议的大小是32x32,但是实践证明23x23或24x24工作起来更好,32x32是被缩放到那么大了再显示出来的。

   属性的属性

   说起来有点绕口,也有点费解,是吗?。vb允许为控件的每个成员设置属性。这里面包含了一些较高级的内容,能够让你建造更为专业化的控件。在菜单栏中点击工具|过程属性,会出现下面的对话框:

   你可以在描叙框内输入一段对控件的说明,在帮助上下文标识符内输入一个帮助的关联id号,将你的控件与一个帮助文件关联起来,这样当点了属性后再按f1键就可以给出这个属性的帮助内容。

   利用“在属性浏览其中使用本页”字段,可以给控件的定制属性页分配选定的号码。这样当用户从vb的属性浏览器中选择该成员时,vb将直接线是属性页。 “属性分类”字段能够让属性在vb的属性浏览器的“按分类序”模式中出现在特定的类别下。这些类别包括外观,字体,位置,杂项等等,只要选择一项就行了。“隐藏该成员”可以让属性不在属性浏览器中显示出来,这对于一些不想让用户看到得公有成员有用,但是要记住,它只是隐藏而不是不许被使用。而利用“在属性浏览器中不显示”可以在控件的设计时(而不是在运行时)把属性从属性浏览器中去掉。作为一般的原则,任何用readproperties和writeproperties实现的永久的属性,都应当被属性浏览器显示出来,反之,任何非永久性的属性就不应被显露出来。

   “缺省用户界面”用来设置控键的缺省属性和方法。比如,因为caption属性是lable控键的缺省属性,那么就可以对代码进行一些简化,把

   label1.caption = "hello"

   可以简写为:

   label1 = "hello"

   最后是关于数据绑定的部分。在vb中,数据库的应用是很常见的。利用ms的数据访问功能,可以很容易的把控件属性和数据库的字段联系起来。当选择了“属性为数据绑定”和“绑定属性到数据字段”两个复选框后,该属性就可以以标准绑定控键的方式运行,这意味着你可以在为该属性选择数据库控件和字段名称。

   最后的话

   到这儿,几乎大部分和用户控件有关的内容都讲完了。你现在就可以开始为自己的程序定制合适的控件,还可以让别人分享你的成果。虽然内容不是很多,但要完全吃透也不是件容易的事。所以,多看多练还是必要的,学无止境嘛。

   当然,没有十全十美的东西,对于activex控件也是这样的。合理的使用用户控件是必须要注意的事情。activex控件很容易就会变得很复杂,一不小心的话,你所付出的会远远多于你所得到的。

   如果你只是想要一个带有属性和方法的对象,那么类或许是更好的选择。用户控件与应用程序间相对复杂的接口,会占用较多的资源。而在编程方面,控件也要比类复杂一些。但是如果你要求属性,方法和事件实现永久的数据存贮,后者要在程序的外部实现组件更新,那么就要用到用户控件了。总之,不要以为这是一件容易的是。虽然我在这儿讲得很简单,但是对一个完整的用户控件的设计,编写,以及测试和调试所作的工作,绝对不会比一个一般的vb应用程序来的少。