VBA:Application.Screen更新Excel功能区上操作的等效项

VBA:Application.Screen更新Excel功能区上操作的等效项,excel,vba,Excel,Vba,我有一个宏,它使用UI自动化框架执行一些操作。我希望在宏执行期间抑制功能区上的快速移动,并希望在最后简单地显示结果。我尝试过使用应用程序。屏幕更新,但这似乎是一个不适用于功能区的设置。 是否有任何设置可用于操纵Excel功能区的屏幕更新 编辑:自动化框架可以在VBA项目中被引用为UIAutomationClient。dll文件是UIAutomationCore.dll 谢谢总结 LockWindowUpdate:不可靠的解决方案 WM_SETREDRAW:一个(太?)强大的解决方案 SW_:一个

我有一个宏,它使用
UI自动化
框架执行一些操作。我希望在宏执行期间抑制功能区上的快速移动,并希望在最后简单地显示结果。我尝试过使用
应用程序。屏幕更新
,但这似乎是一个不适用于功能区的设置。 是否有任何设置可用于操纵Excel功能区的屏幕更新

编辑:自动化框架可以在VBA项目中被引用为
UIAutomationClient
。dll文件是
UIAutomationCore.dll

谢谢

总结
  • LockWindowUpdate:不可靠的解决方案
  • WM_SETREDRAW:一个(太?)强大的解决方案
  • SW_:一个微妙的解决方案
  • 1) LockWindowUpdate:不可靠的解决方案 似乎有人建议使用Windows API函数:
    LockWindowUpdate
    。主要问题是,根据我所做的测试和我发现的两篇帖子,它似乎不可靠:

    • (不适用于所有机器)
    • -您可以在第二篇文章中阅读以下内容: LockWindowUpdate不适用于窗口重画的通用抑制。LockWindowUpdate功能的目的是允许在窗口上绘制拖放反馈,而不受窗口本身的干扰。其目的是在绘制反馈时锁定窗口,在反馈完成时解锁窗口

    但是,如果您想自己测试它,可以在模块顶部使用以下命令声明它:

    因此,通过提供与之交互的工作簿的窗口句柄(必须是顶部窗口),可以临时冻结该窗口。例如,您可以添加:

    'WindowHandle declaration
    #If VBA7 Then
        Private WindowHandle As LongPtr
    #Else
        Private WindowHandle As Long
    #End If
    
    'GetForegroundWindow declaration
    #If VBA7 Then
        Private Declare PtrSafe Function GetForegroundWindow Lib "USER32" () As LongPtr
    #Else
        Private Declare Function GetForegroundWindow Lib "user32" () As Long
    #End If
    
    Sub LockWindow()
        On Error GoTo ErrHandler
        WindowHandle = GetForegroundWindow
        LockWindowUpdate WindowHandle
    
        'Your code here
    
    ErrHandler:
        LockWindowUpdate WindowHandle
    
    End Sub
    
    2) WM_SETREDRAW:一个强大的解决方案 您还可以通过SendMessage窗口API函数发送一条消息,该函数用于防止重新绘制或刷新窗口

    要为Excel工作簿实现此功能,可以使用以下函数声明
    SendMessage
    GetForegroundWindow
    (请参见上面的代码)和适当的常量:

    'SendMessage declaration
    #If VBA7 Then
        Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
    #Else
        Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
    #End If
    
    'SendMessage Message(s)
    Private Const WM_SETREDRAW = &HB
    
    然后,您将围绕代码,如以下示例所示:

    Sub FreezeWorkbook()
    
        On Error GoTo ErrHandler
        WindowHandle = GetForegroundWindow
        Call SendMessage(WindowHandle, WM_SETREDRAW, False, 0&)
    
        'Your code here
    
    ErrHandler:
        Call SendMessage(WindowHandle, WM_SETREDRAW, True, 0&)
    
    End Sub
    
    我还不能用UI自动化命令测试它,但它似乎应该可以工作

    更激烈的选择 <>如果这不起作用,你可能会考虑为整个屏幕做这件事。为此,您需要一个返回桌面句柄的特殊函数:

    'GetDesktopWindow declaration
    #If VBA7 Then
        Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
    #Else
        Private Declare Function GetDesktopWindow Lib "user32" () As Long
    #End If
    
    其余的基本相同:

    Sub FreezeDesktop()
    
        On Error GoTo ErrHandler
        Call SendMessage(GetDesktopWindow, WM_SETREDRAW, False, 0&)
    
        'Your code here
    
    ErrHandler:
        Call SendMessage(GetDesktopWindow, WM_SETREDRAW, True, 0&)
    
    End Sub
    
    请注意,这里使用错误处理更为重要,因为您不希望在出现未处理的错误时整个屏幕保持冻结状态

    [但是,如果发生这种情况,您仍然可以]按键盘睡眠键,然后在进入睡眠状态后, 按唤醒键。。这样可以解冻电脑,避免任何危险 意外丢失数据。()

    3) SW_:一个微妙的解决方案

    如果前一个解决方案干扰了UI自动化过程,您可能需要考虑一个更微妙的解决方案,它可以间接解决您的问题。我说的是在代码开始时最小化窗口,在代码结束时最大化窗口

    这并不完全是您想要的,但至少在交互发生时,用户不会看到窗口。根据我所做的测试,最小化窗口的事实不应该影响UI自动化命令

    'WindowHandle declaration
    #If VBA7 Then
        Private WindowHandle As LongPtr
    #Else
        Private WindowHandle As Long
    #End If
    
    'GetForegroundWindow declaration
    #If VBA7 Then
        Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
    #Else
        Private Declare Function GetForegroundWindow Lib "user32" () As Long
    #End If
    
    'ShowWindow declaration
    #If VBA7 Then
        Private Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal nCmdShow As Long) As Long
    #Else
        Private Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
    #End If
    
    'ShowWindow Commands
    Public Const SW_HIDE = 0
    Public Const SW_SHOWNORMAL = 1
    Public Const SW_NORMAL = 1
    Public Const SW_SHOWMINIMIZED = 2
    Public Const SW_SHOWMAXIMIZED = 3
    Public Const SW_MAXIMIZE = 3
    Public Const SW_SHOWNOACTIVATE = 4
    Public Const SW_SHOW = 5
    Public Const SW_MINIMIZE = 6
    Public Const SW_SHOWMINNOACTIVE = 7
    Public Const SW_SHOWNA = 8
    Public Const SW_RESTORE = 9
    Public Const SW_SHOWDEFAULT = 10
    Public Const SW_MAX = 10
    
    Sub MinimizeAndMaximize()
        On Error GoTo ErrHandler
        WindowHandle = GetForegroundWindow
        ShowWindow WindowHandle, SW_SHOWMINIMIZED
    
        'Your code here
    
    ErrHandler:
        ShowWindow WindowHandle, SW_MAXIMIZE
    
    End Sub
    

    您能更具体地介绍一下您正在使用的UI自动化框架吗?@DecimalTurn,谢谢您的回复!请看编辑后的帖子。谢谢你的回复,我尝试了你建议的第二个选项,但不幸的是,自动化框架操作的功能区似乎变灰了。我想这个函数会影响UI树,自动化框架无法执行它的操作。@ribarcheto94我添加了第三个不应该影响UI树的选项。让我知道这是否适用于您。感谢您花时间添加第三个选项。不幸的是,此宏将用于生产性应用程序,当用户单击按钮时,最小化窗口看起来不专业。我想可能没有什么好办法,但无论如何我都会给你荣誉,因为你为此付出了很多努力。也许其他人会觉得你的建议很有用。@ribarcheto94谢谢!如果您想让它保持专业性,您可以始终显示一个VBA无模式用户窗体,该窗体在最小化Excel窗口时对用户保持可见。你甚至可以包括一个进度条!非常感谢。这是一个新问题:
    'WindowHandle declaration
    #If VBA7 Then
        Private WindowHandle As LongPtr
    #Else
        Private WindowHandle As Long
    #End If
    
    'GetForegroundWindow declaration
    #If VBA7 Then
        Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
    #Else
        Private Declare Function GetForegroundWindow Lib "user32" () As Long
    #End If
    
    'ShowWindow declaration
    #If VBA7 Then
        Private Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal nCmdShow As Long) As Long
    #Else
        Private Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
    #End If
    
    'ShowWindow Commands
    Public Const SW_HIDE = 0
    Public Const SW_SHOWNORMAL = 1
    Public Const SW_NORMAL = 1
    Public Const SW_SHOWMINIMIZED = 2
    Public Const SW_SHOWMAXIMIZED = 3
    Public Const SW_MAXIMIZE = 3
    Public Const SW_SHOWNOACTIVATE = 4
    Public Const SW_SHOW = 5
    Public Const SW_MINIMIZE = 6
    Public Const SW_SHOWMINNOACTIVE = 7
    Public Const SW_SHOWNA = 8
    Public Const SW_RESTORE = 9
    Public Const SW_SHOWDEFAULT = 10
    Public Const SW_MAX = 10
    
    Sub MinimizeAndMaximize()
        On Error GoTo ErrHandler
        WindowHandle = GetForegroundWindow
        ShowWindow WindowHandle, SW_SHOWMINIMIZED
    
        'Your code here
    
    ErrHandler:
        ShowWindow WindowHandle, SW_MAXIMIZE
    
    End Sub