当子例程从其他表单运行时,是否可以单击其他MS Access表单上的按钮?

时间:2019-04-17 19:57:57

标签: vba ms-access access-vba

弹出表格作为Access中的进度栏​​,要添加退出按钮

伙计们,所以我正在尝试为MS Access中的另一种表格制作进度条。进度条本质上是一个很小的弹出窗体,带有与非常耗时的子例程的进度相关联的控件,这里没有任何问题。但是,我试图在进度栏上放置一个“取消”按钮,但是当子例程在后台运行时,我无法在进度栏窗体中单击任何内容。我基本上得到了沙漏图标,我试图用vba代码禁用沙漏图标,但是没有运气。

本质上,我想知道是否有一种方法可以让我在执行子例程时单击其他表单上的按钮。我认为添加我的代码不会帮助您,但如果您希望看到它,请发表评论。谢谢!

1 个答案:

答案 0 :(得分:0)

是的,有可能。使用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工厂方法以 require 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