在子例程运行时,我可以单击MS Access表单上的按钮吗?

问题描述 投票:0回答:1

我有一个进度条,一个小的弹出窗体,链接到一个耗时的子程序的进度。

我正在尝试在进度条上放置取消按钮。当子程序在后台运行时,我无法点击进度条表单中的任何内容。

有没有办法在子程序正在进行时单击不同表单上的按钮?

vba ms-access access-vba
1个回答
1
投票

是的,这是可能的。使用DoEvents告诉VBA继续抽取/处理Windows消息;结果可能不像真正的异步代码那样响应,但应该足以启用单击[取消]按钮并处理取消。


this article中的代码(免责声明:我写的)最初是为Excel编写的,使用的是UserForm(当主机是Access时隐藏在VBE中,但Access VBA项目绝对可以包含和使用UserForm模块)。

您将要删除特定于Excel的位,例如QualifyMacroName

Private Function QualifyMacroName(ByVal book As Workbook, ByVal procedure As String) As String
    QualifyMacroName = "'" & book.FullName & "'!" & procedure
End Function

然后修改Create工厂方法以要求instance参数,如下所示:

Public Function Create(ByVal procedure As String, ByVal instance As Object, Optional ByVal initialLabelValue As String, Optional ByVal initialCaptionValue As String, Optional ByVal completedSleepMilliseconds As Long = 1000, Optional canCancel As Boolean = False) As ProgressIndicator

    Dim result As ProgressIndicator
    Set result = New ProgressIndicator

    result.Cancellable = canCancel
    result.SleepMilliseconds = completedSleepMilliseconds

    If Not instance Is Nothing Then
        Set result.OwnerInstance = instance
    Else
        Err.Raise 5, TypeName(Me), "Invalid argument: 'instance' must be a valid object reference."
    End If

    result.ProcedureName = procedure

    If initialLabelValue <> vbNullString Then result.ProgressView.ProgressLabel = initialLabelValue
    If initialCaptionValue <> vbNullString Then result.ProgressView.Caption = initialCaptionValue

    Set Create = result

End Function

编译完成后,可以通过注册执行实际工作的worker方法来使用ProgressIndicator,如下所示:

With ProgressIndicator.Create("Run", New MyLongRunningMacro, canCancel:=True)
    .Execute
End With

其中MyLongRunningMacro是一个带有Run方法的类模块,可能看起来像这样:

Public Sub Run(ByVal progress As ProgressIndicator)
    Dim thingsDone As Long
    For Each thing In ThingsToDo
        Application.Run thing
        thingsDone = thingsDone + 1
        progress.UpdatePercent thingsDone / ThingsToDo.Count
        If ShouldCancel(progress) Then
            ' user confirmed they want to cancel the whole thing.
            ' perform any clean-up or rollback here
            Exit Sub
        End If
    Next
End Sub

Private Function ShouldCancel(ByVal progress As ProgressIndicator) As Boolean
    If progress.IsCancelRequested Then
        If MsgBox("Cancel this operation?", vbYesNo) = vbYes Then
            ShouldCancel = True
        Else
            progress.AbortCancellation
        End If
    End If
End Function

例如,ThingsToDo可能是要执行的宏的集合。使用循环可以更轻松地报告进度百分比,但是虽然它也可以用于一系列操作,但是干净地处理取消有点困难:

Public Sub Run(ByVal progress As ProgressIndicator)
    Dim thingsDone As Long
    DoThingOne
    If Not UpdateAndContinue(progress, 0.33) Then Exit Sub
    DoThingTwo
    If Not UpdateAndContinue(progress, 0.66) Then Exit Sub
    DoThingThree
    If Not UpdateAndContinue(progress, 1) Then Exit Sub
End Sub

Private Function UpdateAndContinue(ByVal progress As ProgressIndicator, ByVal percentCompleted As Double) As Boolean
    progress.UpdatePercent percentCompleted
    If ShouldCancel(progress) Then 
        ' user confirmed they want to cancel the whole thing.
        ' perform any clean-up or rollback here
        Exit Function
    Else 
        UpdateAndContinue = True
    End If
End Function
© www.soinside.com 2019 - 2024. All rights reserved.