从用户窗体调用 Sheet Sub

从用户窗体调用 Sheet Sub

我正在尝试构建一个宏,它将从我的工作表中的单元格中读取日期,并根据输入到用户窗体中的日期(月份和年份)对其进行检查。为此,我让用户窗体调用Report在 中找到的Sub Sheet1。表示用户输入的月份和年份的整数将随调用一起传递。

错误总是发生在Call Sheet1.Report(intMonth, intYear)调用 的行上: Report。错误内容为:Run-time error '1004': Application-defined or object-defined error

这是我的删节代码,从用户表单开始:

Private Sub cmdOK_Click()

    'Transform month field into an integer (1-12)
    Dim intMonth As Integer
    Select Case cboMonth.Value
        Case Is = strJan 'January - 01
            intMonth = 1
        Case Is = strFeb 'February - 02
            intMonth = 2
        Case Is = strMar 'March - 03
            intMonth = 3
        'and so on...
    End Select

    'Read year field as an Integer
    Dim intYear As Integer
    intYear = txtYear.Value

    Call Sheet1.Report(intMonth, intYear)

End Sub

接下来,这是来自的代码Report。它目前还不完整,因为我无法通过调用。正如我之前提到的,我总是在调用行上遇到错误:Call Sheet1.Report(intMonth, intYear)

Public Sub Report(myMonth As Integer, myYear As Integer)

    'Some incomplete code...
    'Like I said, the macro never gets past the call.

End Sub

有什么办法可以解决这个问题吗?任何帮助都非常感谢。谢谢!

答案1

现在您已经证明您的代码符合我的建议:

ThisWorkbook.Worksheets("Sheet1").Report intMonth, intYear

让我们听取 Mathieu 的建议。单击 VBE 窗口的项目视图中的工作表对象:

VBAProject > Microsfot Excel 对象 > Sheet1 (Sheet1)

第一部分是工作表对象名称,括号中的第二部分是 Excel 选项卡中显示的工作表名称。从 VBE 中的“视图”下拉菜单或按 F4 调出属性窗口视图。工作表属性窗口中的第一项应该是 (name),这是您将在代码中调用的对象名称。将其更改为描述性名称,例如“Report”。然后为您的宏使用描述性名称,例如“Update”。

现在您可以通过调用以下命令来创建新报告:

Report.Update intMonth, intYear

我使用这个命名约定是因为我认为您的宏会更新报告表。您也可以听取他关于“模型-视图-演示者”代码样式的建议,但这有点超出您的问题范围。

答案2

UserForm的默认实例运行也许是最容易的事情,但它也是很多问题的直接原因——从容易引入但难以发现的错误到维护和可扩展性问题:“快速、有效”的解决方案是“智能 UI”模式,它对于原型. 随着时间的推移,规模不断扩大的大型项目需要更加智能的架构。

程序员称之为“模型-视图-演示者”。看法是形式。数据是模型,然后是主持人协调一切。

从用户窗体调用 Sheet Sub

事实是,你不需要。情态动词UserForm对话,其作用无非就是收集用户的输入。通过让它只负责操作数据,而让宏/调用者负责控制流,您可以使代码更加健壮且更易于维护 - 尤其是当表单可以做很多事情时。

从一个简单的类模块开始MonthlyReportParams

Option Explicit
Public Month As Integer ' encapsulate into properties to implement 
Public Year As Integer  ' logic for validation on assignment.

Public Property Get IsValid() As Boolean
    IsValid = Month >= 1 And Month <= 12 And _
              Year >= 1900 And Year <= 2100
End Property

现在要做UserForm的就是处理这些数据,模型

Option Explicit
Private params As MonthlyReportParams
Private cancelled As Boolean

Private Sub Class_Initialize()
    Set params = New MonthlyReportParams
End Sub

Public Property Get Model() As MonthlyReportParams
    Set Model = params
End Property

Public Property Set Model(ByVal value As MonthlyReportParams)
    Set params = value
    MonthBox.value = params.Month
    YearBox.value = params.Year
End Property

Public Property Get IsCancelled() As Boolean
    IsCancelled = cancelled
End Property

Private Sub MonthBox_Change()
    ' make sure the textboxes contain numeric values before assigning to Integer
    If IsNumeric(MonthBox.Value) Then params.Month = CInt(MonthBox.Value)
    OnValidate
End Sub

Private Sub YearBox_Change()
    ' make sure the textboxes contain numeric values before assigning to Integer
    If IsNumeric(YearBox.Value) Then params.Year = CInt(YearBox.Value)
    OnValidate
End Sub

Private Sub OkButton_Click()
    Me.Hide
End Sub

Private Sub CancelButton_Click()
    OnCancel
End Sub

Private Sub OnCancel()
    cancelled = True
    Me.Hide
End Sub

Private Sub OnValidate()
    OkButton.Enabled = Model.IsValid
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' runs when form is just about to close
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        ' user clicked the [X] button
        Cancel = True ' don't destroy the form
        OnCancel
    End If
End Sub

现在,调出此表单的宏可以重新控制正在发生的事情:表单不再运行节目,我们可以在一个地方读取正在发生的所有事情:

Public Sub RunMonthlyReport(Optional ByVal targetSheet As Worksheet = Nothing)

    If targetSheet Is Nothing Then
        ' no sheet was specified; work of the ActiveSheet
        Debug.Assert Not ActiveSheet Is Nothing
        Set targetSheet = ActiveSheet
    End If

    ' create the model
    Dim m As MonthlyReportParams
    Set m = New MonthlyReportParams
    m.Month = Month(Now)
    m.Year = Year(Now)

    ' create the dialog, assign the model
    With New MonthlyReportParamsDialog
        Set .Model = m
        .Show ' next line only runs after dialog has closed

        If Not .IsCancelled Then
            ' run the report with the values in the model
            targetSheet.Report m.Month, m.Year
        End If
    End With

End Sub

关于这种“责任逆转”的好处的更多信息,可以找到在本文中以及进一步的回调逻辑在本文中- 免责声明:我写了这两个博客;该博客是橡皮鸭VBIDE 插件 OSS 项目,我拥有。

答案3

HackSlash 回答了我的问题:

您的代码示例对我有用。请记住,您使用“Sheet1”作为对象是工作表对象名称,而不是实际 Excel 工作表选项卡上显示的工作表名称。如果您想通过工作表名称调用它,请尝试以下操作:ThisWorkbook.Worksheets("Sheet1").Report intMonth, intYear 注意:如果删除括号,则不需要 Call 语句。– HackSlash 7 分钟前

相关内容