搞了快一个下午的这个东东, 其实是在搞一个在VB6.0中动态添加控件和时间的一个实现, 没用过VB6.0, IDE也么有VS好用... 好多东东在探索结果就报了个这个错误....run-time error '91' object variable or with block variable not set查了好久, 原来是使用变量的时候, 没有去new它, 因为别人给的sample中, Dim的时候, 有new, 单身我拿过来用的时候, dim后面的new在build的时候不通过, 我就拿掉了, 结果运行的时候一直出这个问题..动态添加控件和时间的, 参考如下(等哪天我有空了,再来写)创建数据驱动窗体所谓数据驱动窗体就是根据所请求的数据的不同生成相应的窗体。
举例来讲,假设你现在有一个数据库,其中有些字段必须根据登录者的身份加以显示,授权级别高的用户可以浏览并修改这些字段的内容;授权级别一般的用户只能浏览这些字段中的数据;授权级别低的用户则不能浏览这些字段中的内容。
要做到这一点就得利用VB动态添加控件的功能。
动态创建控件无论你想要创建何种类型的数据驱动窗体,你必须知道如何在运行时动态地创建控件。
你可以通过控件数组做到这一点,但VB6的Controls集合所提供的Add方法,功能更强大,灵活性更高。
使用该方法,你不需要在设计时将控件的实例放在窗体上。
实际上,用Add方法你甚至可以创建程序在编译时根本不存在的控件。
这种方法的用法也很简单:' 声明一个窗体级的变量Dim WithEvents txtTotal As TextBoxSub CreateTextbox()' 创建新的Textbox控件Set txtTotal = Controls.Add("VB.TextBox", "txtTotal")' 将控件移动到你所需要的地方txtTotal.Move 1000, 800, 1200, 300' 创建时,所有的控件都是不可见的txtTotal.Visible = TrueEnd Sub请注意Add方法的第二个参数:分配给控件的名称。
从代码可读性出发,这个名称一般都与变量名相同。
你可以用这个名称从Controls集合中获取相应的控件或移除该控件。
例如:Controls.Remove "txtTotal"在变量声明时加上WithEvents关键字,即使在设计时窗体不存在该控件,你也可以为该控件的事件编写代码。
上面所讲的方法只适合解决VB内置的控件。
例如,当你要添加一个TreeView控件时,VB会要求你证明你已经得到了合法的授权来创建该控件的实例。
换句话说,VB要证明这个控件是买来的,而不是从其它附有该控件的程序中借来的。
要证明你经过了合法的授权有下面几种方法:在窗体上放置一个控件。
这也是最简单的方法。
你完全没有必要将这个窗体显示出来。
将相关的控件添加到工具箱中,然后在“工程属性”对话框的“生成”标签页中取消选择“删除有关未使用的ActiveX控件的信息”这一项。
向Licenses集合添加一个元素。
例如:Debug.Print Licenses.Add("MSMask.MaskedEdBox")仅仅创建了控件并不足够要创建一个数据驱动窗体,仅仅知道动态创建控件还不够。
例如:现在你要创建一个能根据数据库中表的不同字段自动生成控件的窗体。
该窗体可能会创建单行文本框,其长度随字段长度不同而不同;也可能会创建单选按钮或复选按钮以显示布尔型字段;甚至可能创建一个多行文本框显示备注型字段。
你需要解决的第一个问题是:文本框控件的Multiline属性在运行时是只读的,只在设计时可用。
幸好,微软的Microsoft Windowless Controls 6.0可以解决这个问题。
这组控件集包括了轻量级的TextBox,ComboBox,ListBox,CheckBox,OptionButton,CommandButton和两个scrollbar控件。
这些控件与VB内置的相应的控件最大的区别在于:这些控件的所有属性在运行时是可读写的。
在VB的安装光盘中的Common\Tools\VB\WinLess文件夹中可以找到这个控件组。
用下面的代码可以创建一个多行文本框:Dim WithEvents txtEditor As MSWLess.WLTextPrivate Sub CreateEditor()Set txtEditor = Controls.Add( "MSWLess.WLText", "txtEditor")txtEditor.Move 0, 0, 4000, 4000txtEditor.MultiLine = TruetxtEditor.ScrollBars = wlBothtxtEditor.Visible = TrueEnd Sub另外一个问题比较复杂:在事先不知道要创建多少个控件的情况下,如何给每个对新创建的控件的引用分配唯一的带WithEvents关键字的变量。
换句话说就是要对新创建的控件的事件进行编程,前提是你在设计时不知道程序会创建多少个控件。
使用对象数组显然不行,因为不能用WithEvents关键字声明一个对象数组;更坏的情况是,资一个变量定义为As Control或As Object也不行,因为还是不能用WithEvents。
问题源自于我们无法在运行时捕获一个对象数组事件。
所以我们只能采取曲线救国的办法。
所要的编写的代码可能比你想象的多,不过这个解决方法很有趣,值得我们这样去做。
我们需要两个辅助类模块来捕获事件,分别取名为ControlItems和ControlItem。
ControlItems是一个集合类,其中保存了ControlItem对象及其数量。
该数量等于你所要对之编程的控件的数量。
ControlItem 类的每一份实例捕获控件产生的事件,然后调用在其所属的ControlItems集合类中的过程,最后由ControlItems在窗体中触发事件并执行事件中的代码。
整个过程如下图所示:捕获多个控件的事件为简单起见,假设你要捕获来自所有的动态添加到窗体上去的控件的Validate事件。
为完成这个工作,ControlItems集合类必须向父窗体展示该事件,并随时准备接收来自其子ControlItem类的通知以触发事件。
代码如下:Event Validate(CtrlItem As ControlItem, Cancel As Boolean)Private m_ControlItems As New Collection' 向集合中添加一个新的ControlItem项目Function Add(ctrl As Control) As ControlItemDim newItem As New ControlItemnewItem.Init ctrl, Me' 添加到私有类m_ControlItems.Add newItem' 返回新项目给调用者Set Add = newItemEnd FunctionFriend Sub Notify_Validate(Item As ControlItem, Cancel As Boolean)RaiseEvent Validate(Item, Cancel)End SubControlItem类必须捕获来自动态添加到窗体中的控件的事件,并通知其所属的ControlItems集合类。
很显然,ControlItem类必须有一个用WithEvents关键字定义的变量来引用真正的控件。
这意味着你不能将变量声明为As Control或As Object。
如果你决定在窗体中所动态添加的控件不使用VB内置的控件的话,这个问题的解决办法相当的简单。
你只需要将变量声明为VBControlExtender类型就行了。
对于创建数据驱动窗体来讲,不使用VB内置的控件并不是一件大不了的事。
将变量声明为VBControlExtender,并加上WithEvents关键字,你就能直接捕获以使用ObjectEvent。
下面是ControlItem类模块中的代码:Public WithEvents Ctrl As VBControlExtender' 所属的ControlItems对象Dim m_Parent As ControlItemsSub Init(ctl As Object, parnt As ControlItems)Set Ctrl = ctlSet m_Parent = parntEnd SubPrivate Sub Ctrl_Validate(Cancel As Boolean)' 通知所属的ControlItems类m_Parent.Notify_Validate Me, CancelEnd Sub将下面的代码放入窗体中,就可以捕获动态添加的控件所产生的事件了:Dim WithEvents CtrlItems As New ControlItemsPrivate Sub cmdCreateControls_Click()Dim ctrl As Control' 创建两个文本框并将它们添加到ControlItems集合? Set ctrl = Controls.Add("MSWLess.WLText", "One")ctrl.Move 100, 200, 1000, 300ctrl.Visible = TrueCtrlItems.Add ctrl' 注意你可以使用同一个变量Set ctrl = Controls.Add("MSWLess.WLText", "Two")ctrl.Move 100, 800, 1000, 300CtrlItems.Add ctrlEnd SubPrivate Sub CtrlItems_Validate( CtrlItem As ControlItem, Cancel As Boolean)' 拒绝空字符串 - 注意如何引用控件的属? If CtrlItem.Ctrl.Text = ""Then Cancel=TrueEnd Sub现在解决了最困难的部分,要创建一个数据驱动窗体就变得简单了******************************************************************************************************************************动态添加控件VB6有一个新功能,可以动态添加控件,不用控件数组:object.Add (ProgID, name, container)参数说明Object 必需的。