只是一个我似乎无法找到答案的问题。
我以编程方式创建了一个用户表单,并且我发现如果我将对象声明为类型" MSForms.Userform"似乎没有办法设置高度和宽度,因为这些属性不存在,而insideheight / insidewidth是只读属性。
我发现如果我将其声明为通用类型" object",我可以设置高度和宽度属性并完全按照我的意愿使用它。
因此,在初始化对象后,我检查了本地窗口,差异似乎是:
所以我的问题是,使用不同的声明语句有什么区别?
谢谢!
编辑:添加了一些示例代码,以便您可以看到对象在不同声明时的行为方式有何不同。
(我无法正确显示此代码块 - 即使声明为基本语言)
Sub TestUserForm()
'NOTE: You need to add a reference to Microsoft Visual Basic
' for Applications Extensibility 5.3
'Declare variables
Dim oForm As MSForms.UserForm
Dim oForm1 As Object
Dim oComp As VBComponent
Dim oComp1 As VBComponent
'Create new form objects in the VBA project programmatically
Set oComp = Application.VBE.ActiveVBProject.VBComponents.Add(ComponentType:=vbext_ct_MSForm)
Set oComp1 = Application.VBE.ActiveVBProject.VBComponents.Add(ComponentType:=vbext_ct_MSForm)
'Initailize an object of each new form
Set oForm = VBA.UserForms.Add(oComp.Name)
Set oForm1 = VBA.UserForms.Add(oComp1.Name)
'Compare what happends when trying to set the width and height properties
With oForm1 'This works
.Height = 200
.Width = 100
End With
With oForm1 'This does not work
.Properties("Width") = 100
.Properties("Height") = 200
End With
With oForm 'This does not work
.Height = 200
.Width = 100
End With
With oForm 'This does not work
.Properties("Width") = 100
.Properties("Height") = 200
End With
'Remove the forms from the project
Application.VBE.ActiveVBProject.VBComponents.Remove oComp
Application.VBE.ActiveVBProject.VBComponents.Remove oComp1
End Sub
答案 0 :(得分:8)
将组件导入项目时,它将分别命名为UserForm1
和 UserForm2
。
oForm == UserForm1
oForm1 == UserForm2
现在,看MSDN docs for Object,我们发现:
在过程运行之前,如果不知道特定对象类型,则可以使用Object数据类型声明对象变量。使用Object数据类型创建对任何对象的通用引用。
你已经声明了这样的变量:
Dim oForm As MSForms.UserForm
Dim oForm1 As Object
初始化对象时会发生什么,oForm
被初始化为UserForm,而运行时确定 Object oForm1
是UserForm1的一个实例,这是不一样的。
在初始化之前尝试更改oForm1的组件名称,您应该很快就会看到差异。
现在 ,如果您希望声明类型安全性为通用表单 和 ,则需要访问Width
属性,您可以将UserForm强制转换为Object并像这样访问它。
Dim FormAsForm As UserForm
Dim FormAsObject As Object
Set FormAsForm = New UserForm1
Set FormAsObject = FormAsForm
FormAsObject.Width = 200
Debug.Print TypeName(FormAsForm)
Debug.Print TypeName(FormAsObject)
这是我们在实现多个接口时经常使用的技巧。编译器只允许您使用在声明类对象的特定类型中定义的属性。
那有什么区别?实际上,在将事物声明为Object时,您没有智能感知。你也没有类型安全。这样做完全有效(虽然不推荐。)
Dim foo As New Baz
Dim bar As New Qux
Dim var As Object
Set var = foo
Set var = bar
当您使用后期绑定时,对象确实非常方便,以避免添加对项目的引用。如果没有添加引用,您将被迫使用未知类型。
Dim xl As Object
Set xl = CreateObject("Excel.Application")
另一个很大的区别是你将它留给运行时来确定变量将是什么类型的对象。正如您所发现的,它有时(很少,但有时)会产生令人惊讶的结果。
答案 1 :(得分:1)
我认为你对这种差异有了答案:
但编译器只允许使用类对象声明为的类型的现有属性/方法:
我做了一些测试,我只是想指出我认为纠正的程序宁愿:
Dim FormAsForm As **UserForm1***
Dim FormAsObject As Object
Set FormAsForm = New UserForm1
Set FormAsObject = FormAsForm
FormAsObject.Width = 200
Debug.Print TypeName(FormAsForm)
Debug.Print TypeName(FormAsObject)
将FormAsForm声明为UserForm1,而不是UserForm,这会导致我的错误:
运行时错误'438':对象不支持此属性或方法
然而,使用它,在使用.Show加载并显示一次FormAsForm之后,然后将Unloaded,FormAsForm从TypeForm11 / UserForm11下载到UserForm11 / UserForm,并且无法再显示.Show。任何应该工作的方法都会导致这个错误:
错误'-2147418105':自动化错误
错误'-2147418105':Erreur Automation:L'appelé(serveur [pas application serveur])n'est pas disponible et disparu; aucune connexion n'est valide。 L'Appel a peut-êtreétéexécuté。
当然,我刚给出的变量类型是从Locals VBE窗口中读取的,因为?TypeName(FormAsForm)只会带来:
运行时错误'13':输入不匹配
对于记录,?TypeName(FormAsObject)在向下转换后返回UserForm,而.Show方法会导致相同的“自动化错误”。
这一部分,我无法解释......
答案 2 :(得分:0)
因此,除非我在这里错过我的猜测,否则MSFORMS.UserForm是其他某些东西的子类(也许类似于VB6 Form类?),以及它在按尺寸标注时可以正确处理的其他属性和方法。对象(.Hide,.Show,.Visible,以我到目前为止所知道的命名)既不是Userform类接口的一部分,也不是文档化的ANY-DAMN-WHERE-AT-ALL(而且我不会除了阅读有关UserForms的在线问题/评论外,我不了解上面列出的内容! ...必须派生自UserForm继承的基类?
太糟糕了,我们看不到基类是什么,因为这样我们就可以找到有关我们可以使用的其他功能的实际线索(谁知道,可能有.Parent,.Properties或其他有趣的东西)似乎没有人知道的“在那里”的东西。