excel - 如果 excel-vba 无模式用户窗体窗口重新获得焦点,会触发哪个事件?

标签 excel vba

我在 Excel VBA 项目中有一个无模式用户窗体。 用户表单通过单击电子表格上的按钮来加载(如果相关,则不是 active-x 按钮)。 由于无模式,用户可以使用 Excel 甚至其他应用程序,而不是切换回表单窗口。 我需要一个在表单窗口再次成为事件窗口时触发的事件。我想 UserForm_Activate应该完成这项工作,但它没有(UserForm_GotFocus 也没有,但用户表单没有 GotFocus 事件?)。如果用户切换回无模式用户窗体(或者如果没有:是否有任何已知的解决方法),是否会触发任何事件?或者我这里有一些奇怪的错误和Activate应该开火吗?

这是我用于测试目的的所有代码:

' standard module:

Sub BUTTON_FormLoad()
    ' associated as macro triggered by button click on a sheet
    UserForm1.Show vbModeless
End Sub


' UserForm1:

Private Sub UserForm_Activate()
    ' does not fire if focus comes back
    Debug.Print "Activated"
End Sub

Private Sub UserForm_GotFocus()
    ' does not fire if focus comes back
    ' wrong code - no GotFocus event for userforms?
    Debug.Print "Focussed"
End Sub

Private Sub UserForm_Click()
    ' only fires if clicked *inside* form
    ' does not fire eg if user clicks top of form window
    Debug.Print "Clicked"
End Sub

在哪里可以找到用户窗体事件的文档?它不在'UserForm object上' 页面。

最佳答案

当您在应用程序和无模式用户窗体之间切换时,不会触发 Activate 事件。这是设计使然。

就像我在评论中提到的

You can achieve what you want by subclassing the userform and trapping the worksheet events but it very messy.

这是一个非常基本的示例。示例文件可以从Here下载

先读我:

  1. 这只是一个基本示例。请在测试之前关闭所有 Excel 文件。
  2. 如果用户直接单击用户表单上的控件,并且您也想在那里运行激活代码,那么您也必须处理该问题。
  3. 一旦您满意,就可以修改它以满足您的需要。

将代码放入模块

Option Explicit

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long

Private Declare Function SetWindowLong& Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long)

Private Const GWL_WNDPROC = (-4)
Private WinProcOld As Long
Private Const WM_NCLBUTTONDOWN = &HA1

Public formWasDeactivated As Boolean

'~~> Launch the form
Sub LaunchMyForm()
    Dim frm As New UserForm1
    frm.Show vbModeless
End Sub

'~~> Hooking the Title bar in case user clicks on the title bar
'~~> to activate the form
Public Function WinProc(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If wMsg = WM_NCLBUTTONDOWN Then
        '~~> Ignoring unnecessary clicks to the title bar
        '~~> by checking if the form was deactivated
        If formWasDeactivated = True Then
            formWasDeactivated = False
            MsgBox "Form Activated"
        End If
    End If

    WinProc = CallWindowProc(WinProcOld&, hwnd&, wMsg&, wParam&, lParam&)
End Function

'~~> Subclass the form
Sub SubClassUserform(hwnd As Long)
    WinProcOld& = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WinProc)
End Sub

Sub UnSubClassUserform(hwnd As Long)
    SetWindowLong hwnd, GWL_WNDPROC, WinProcOld&
    WinProcOld& = 0
End Sub

创建用户表单。我们将其命名为Userform1。在表单中添加命令按钮。我们将其命名为 CommandButton1

将代码放入用户表单

Option Explicit

Private Declare Function FindWindow Lib "user32.dll" _
Alias "FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long

Dim hwnd As Long

Private Sub UserForm_Initialize()
    hwnd = FindWindow(vbNullString, Me.Caption)
    SubClassUserform hwnd
End Sub

'~~> Userform Click event
Private Sub UserForm_Click()
    '~~> Ignoring unnecessary clicks
    '~~> by checking if the form was deactivated
    If formWasDeactivated = True Then
        formWasDeactivated = False
        MsgBox "Form Activated"
    End If
End Sub

'~~> Unload the form
Private Sub CommandButton1_Click()
    '~~> In case hwnd gets reset for whatever reason.
    hwnd = FindWindow(vbNullString, Me.Caption)
    UnSubClassUserform hwnd

    Unload Me
End Sub

将此代码放入工作簿代码区域

Option Explicit

'~~> Checking if the form was deactivated
'~~> Add more events if you want

Private Sub Workbook_SheetActivate(ByVal Sh As Object)
    formWasDeactivated = True
End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    formWasDeactivated = True
End Sub

请随时添加更多工作簿事件。我只使用了 Workbook_SheetActivateWorkbook_SheetSelectionChange

最后在工作表中添加一个表单按钮,并将宏 LaunchMyForm 分配给它。我们就完成了

实际行动

enter image description here

关于excel - 如果 excel-vba 无模式用户窗体窗口重新获得焦点,会触发哪个事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58193383/

相关文章:

excel - 按月统计发生次数

vba - "As Dictionary"和 "As Scripting.Dictionary"是否等效(对于 VBA 早期绑定(bind))?

vba - 使用 VBA 将 Excel 中的范围粘贴到 Powerpoint 模板的某些幻灯片中

excel - 处理 CSV 数据

vba - 使用Excel VBA,如何将相同值的多行复制到新工作表中?

excel - 如何跨范围复制excel文件中的单元格格式?

excel - 长数据类型溢出

excel - 如何制作一个像数字 watch 一样的定时器?

vba - 从绘图中保存模型

javascript - 尝试使用 Excel VBA 从剑道弹出窗口中提取值