【问题标题】:How to set focus to a Frame that overlays other controls, and still have the Frame visible on top of other controls如何将焦点设置到覆盖其他控件的框架,并且仍然使框架在其他控件之上可见
【发布时间】:2021-08-26 15:35:02
【问题描述】:

我有一个独立的类文件,用于创建和操作日期选择器。它仅使用本机 VBA 控件,不使用内核调用,也不需要任何模块文件。它接受鼠标或键盘输入来选择日、月和/或年。它可以在类似于弹出对话框的用户窗体上实例化。或者它可以在 Frame 上实例化,其行为类似于覆盖。我的问题是后者,其中 Frame 不会覆盖 UserForm 上的其他控件,例如列表框或多页表单,并且在它们共享地理位置的地方隐藏。

我已经成功地让 Frame 始终覆盖 UserForm 上的所有内容,但此时 Frame 没有焦点。操作日期选择器需要单击鼠标,因为它无法识别任何键盘输入。如果我在生成日期选择器时在类中执行 setFocus,或者在生成日期选择器后调用类,则日期选择器 Frame 再次位于表单上的其他控件后面。

此外,在开发过程中,在日期选择器可见之后和 setFocus 执行之前在类中放置一个断点,当恢复执行时,框架会覆盖所有内容并响应键盘输入。因此,在允许这种情况发生的开发环境中发生了一些事情。我试图实现一个小的延迟循环,希望它能复制一些东西,但它没有。

有没有人对如何在框架可见后将焦点移动到框架并使其保持在所有控件之上的建议?从我在 Stackoverflow 中看到的情况来看,这个问题过去曾被提出并回答过,但没有任何真正的解决方案。

示例代码: 创建一个用户窗体并将一个标签、一个列表框和一个框架放在窗体上的任何位置。对于这些项目中的任何一个,位置和大小都无关紧要。 在 UserForm 的代码中放置此代码。

    Dim aClass As CDatePicker
    Private Sub Label1_Click()
        aClass.setSelectedDate Label1
    End Sub

    Private Sub UserForm_Initialize()
        Set aClass = New CDatePicker
        aClass.makeCalendar Nothing, Frame1
    End Sub

创建一个类模块并将这段代码粘贴到那里

    Option Explicit

    Private WithEvents aKey As MSForms.TextBox
    Private WithEvents lCancel As MSForms.Label
    Private aFrame As Object
    Private Sub lCancel_click()
                aFrame.Visible = False
    End Sub
    Private Sub aKey_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)

        Select Case KeyCode
                Case 99, 67:    lCancel_click
                Case 27:        lCancel_click
                Case Else: aFrame.Caption = Chr(KeyCode)
        End Select
        KeyCode = 0
    End Sub

    Sub makeCalendar(oTheDate As Object, aForm As Object)
        Set aFrame = aForm
        With aFrame
                .Visible = False
                .Width = aForm.Parent.Width - 18
                .Height = aForm.Parent.Height - 38
                .Top = 3
                .Left = 3
                .ZOrder (0)  ' this is what makes the frame overlay all controls
                .Caption = ""
        End With
        
        Set aKey = aFrame.Controls.Add("forms.textbox.1", "aKey", True)
        With aKey
                .Height = 2
                .Width = 2
        End With
        
        Set lCancel = aFrame.Controls.Add("forms.label.1", "lCancel", True)
        With lCancel
                .Top = 50
                .Left = 5
                .BorderStyle = fmBorderStyleSingle
                .SpecialEffect = fmSpecialEffectRaised
                .Caption = "Cancel"
                .TextAlign = fmTextAlignCenter
        End With
    End Sub
    Sub setSelectedDate(lCkDate As Object)
        With aFrame
                .Visible = True
        End With
        aKey.SetFocus
    End Sub

当您单击标签时,会显示框架,但列表框会覆盖框架并且仍然可见。键入任意键,Frame Caption 将显示该键。

如果您在类中注释最后一行(aKey.setFocus),然后单击标签,则显示框架,并且列表框不可见。键入任何键,没有任何反应。如果您单击 Frame 上的任意位置,然后键入任意键,Frame Caption 将显示该键。

如果您在类的最后一行 (aKey.setFocus) 上放置一个断点,然后单击标签,则会显示框架。列表框不可见。继续执行,键入任何键,框架标题将显示该键。

有没有办法在开发环境之外复制这种行为?

【问题讨论】:

标签: excel vba


【解决方案1】:

这在我看来是一个时间问题,然后我通常使用 application.ontime:

添加一个模块:

Sub DoStuff(tb As String)
Dim ctl As Control
For Each ctl In UserForm1.Controls 'for easiness opening default instance of Userform1)
    If ctl.Name = tb Then ctl.SetFocus
Next
End Sub

并调整您的“setSelectedDate”代码如下:

Sub setSelectedDate(lCkDate As Object)
    With aFrame
            .Visible = True
    End With
 ' aKey.SetFocus
       Application.OnTime Now(), "'DoStuff " & aKey.Name & "'"
 End Sub

【讨论】:

  • 因为 setSelectedDate 在类模块中,不确定如何在 OnTime 调用中构造 DoStuff 规范以便可以找到它。尝试了 Module1.DoStuff 并没有找到。
  • 感谢 EvR 对解决方案的启发。如果我在 Frame 可见之后和 setFocus 之前添加一个 DoEvents,它会起作用。
【解决方案2】:

我发现了解决方案:在使 Frame 可见之后和在 Frame 上设置焦点之前添加一个 DoEvents 语句。 Frame 保持在“顶部”,它还处理键盘输入。

【讨论】:

    【解决方案3】:

    我建议以这种方式更改类setSelectedDate 方法:

       Sub setSelectedDate(lCkDate As Object)
            With lCkDate
                .Visible = True
                .ZOrder (0)
                .SetFocus
            End With
        End Sub
    

    以及要转换成的调用事件:

        Private Sub Label1_Click()
            aClass.setSelectedDate Frame1
        End Sub
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-20
      • 2011-07-23
      • 1970-01-01
      相关资源
      最近更新 更多