VBA- UserForm.Lable.Caption获取错误91对象未设置

时间:2017-11-06 15:38:33

标签: excel vba excel-vba runtime-error

系统描述:我有一个userform,它接受正在返回的项目的输入。用户单击需要返回的项目的行,然后单击“签入按钮”

我的尝试:我在电子表格上创建了​​一个按钮 checkin_cmdbutton ,用于衡量选择了哪个单元格选择的项目 Application.ActiveCell.Row ,将信息写入userform Checkin_Form ,用户完成其余的登记信息,然后点击提交。
此代码是电子表格中按钮 checkin_cmdbutton 的事件:

 Private Sub checkin_cmdbutton_Click()
       Set ItemID = Cells(Application.ActiveCell.Row, 1)
       Set ItemDescription = Cells(Application.ActiveCell.Row, 2)

       If ItemID Is Nothing Then
           MsgBox ("ID is null, ending...")
           Exit Sub
       End If

       Checkin_Form.UserForm_Initialize
       Checkin_Form.itemid_dynamiclabel.Caption = ItemID.Value
       Checkin_Form.description_dynamiclabel.Caption = ItemDescription.Value
       Checkin_Form.checkin_datepicker.Value = Date
       Checkin_Form.Show 
End Sub

问题:代码在 Checkin_Form.itemid_dynamiclabel.caption 和以下2行引发错误91“对象变量或未设置块变量”。为什么表单上的对象会抛出此错误?我不能宣布这些,可以吗?

2 个答案:

答案 0 :(得分:2)

您不应该明确地调用UserForm_Initialize - 这是一个事件处理程序,默认情况下处理程序是Private:它们被调用了当事件提供者认为有必要时 - 在这种情况下,当对象实例被初始化时。

确保表单正确初始化的最佳方法是将其视为对象,而不是将全局状态存储在其默认实例上。

UserForm类只是一个带有设计器和VB_PredeclaredId模块属性的类模块。此属性使VBA创建以类命名的全局范围对象变量,这就是此代码合法的方式:

UserForm1.Show

除此之外,不应该

DON' 想要将全局状态存储在默认实例中:这是您想要的最后一件事,尤其是如果您的表单涉及动态控制。

New而不是。

With New UserForm1
    .Show
    'what follows only executes when the form is closed:
    '...
End With

为此,您必须处理表单的QueryClose事件,以防止在用户单击[X]按钮时对象实例自行毁坏。

要使其正常工作,您还必须避免破坏表单,例如:使用Unload Me(或更糟,Unload UserForm1)来电 - 例如,当用户点击[确定]按钮时。相反,您Hide(或Me.Hide)表单,以便调用者(New'它的代码)仍然可以访问对象的状态

从你的代码的外观 - 即.Show调用是你的宏所做的最后一件事,我可以告诉你,你有表格运行show:这是一个反模式每当你这样做时都会产生问题。

表单不实现应用程序逻辑:表单存在并收集数据。没有更多,没有更少。写入任何电子表格,甚至不了解工作表,这不是表格的工作。

Read this recent article of mine如果您想了解有关正确表单的更多信息。

现在,实际问题。

Checkin_Form.itemid_dynamiclabel.Caption = ItemID.Value

如果该标签是动态(即在运行时创建),那么我很惊讶地访问它甚至编译。首先,删除表单名称中的下划线:下划线在VBA中具有特殊含义 - 我确定您现在已经注意到VBA如何为给定对象生成事件处理程序:

Private Sub ObjectName_EventName()
End Sub

如果ObjectNameEventName有下划线,那么您要求在某个时刻要求编译错误 - 有一天您会想要使用Implements语句,发现你的代码不能被编译,如果你保持这种下划线的习惯:现在更好地失去它。

如果控件是动态的,那么您就无法按照自己的方式执行操作。

需要通过表单Controls集合

来访问动态控件
Dim myLabel As MSForms.Label
Set myLabel = Me.Controls("NameOfTheLabelControl")

否则,您需要在模块级别保留对动态控件的引用,在代码隐藏的形式中 - 您可以通过属性公开它:

Option Explicit
Dim myLabel As MSForms.Label

Private Sub UserForm_Initialize()
    Set myLabel = Me.Controls.Add(...)
End Sub

Public Property Get ThatLabel() As MSForms.Label
    Set ThatLabel = myLabel
End Property

或者更好的是,使用实际的模型类,让调用代码完全不受控件的影响 - 请参阅之前链接的文章了解详细信息。

TL; DR:

您收到该错误是因为您的标签对象实例未初始化,即它Nothing。由于您没有显示您的表单代码隐藏,我们无法指出为什么会出现这种情况,但我的资金存在于表单默认实例< / em>让你成为&#34的另一个受害者;嘿看它有多容易!&#34;教导错误的VBA教程。

在表单外部实现工作表处理代码,使表单收集数据,使表单隐藏后调用代码读取此数据,然后使调用代码创建并销毁表单实例。

现在,尽管如此,我不知道为什么你认为你需要动态控制。

答案 1 :(得分:0)

只是在黑暗中拍摄,只要我真的不知道你的变量的名称和它们是什么(一些截图将有所帮助)。如果你的代码是一个表格(就你所知_Click我认为是这样的话),试试这样:

 Private Sub checkin_cmdbutton_Click()
       Set ItemID = Cells(Application.ActiveCell.Row, 1)
       Set ItemDescription = Cells(Application.ActiveCell.Row, 2)    

       Me.itemid_dynamiclabel.Caption = ItemID.Value
       Me.description_dynamiclabel.Caption = ItemDescription.Value
       Me.checkin_datepicker.Value = Date
       Me.Show 
End Sub

并尝试至少声明变量(例如ItemID等)并在顶部使用Option Explicit