【问题标题】:How do I create a command button that tells me which control had FOCUS?如何创建一个命令按钮来告诉我哪个控件具有 FOCUS?
【发布时间】:2012-02-19 02:05:39
【问题描述】:

我在我的 VB6 表单上放置了一个命令按钮。我想这样做,如果我单击此按钮,它将弹出一条消息,指示最近哪个控件具有 FOCUS。

我知道如果我按下命令按钮,它将导致命令按钮获得焦点。我有兴趣在命令按钮将焦点移开之前找出哪个控件具有焦点。我该怎么做?

【问题讨论】:

  • 可能不是最佳答案,但有可能......不再 100% 熟悉 vb6。有一个变量来存储当前具有焦点的控件,除了显示最后点击的控件的按钮(这只会显示自己)?其他人可能有更好的东西。所以我只是添加这个评论。
  • 好的,谢谢你的评论,我会考虑的。

标签: forms vb6 focus controls


【解决方案1】:

Subclass 按钮。
处理WM_SETFOCUS.
采取相应的行动。

示例。

表格Form1:

Option Explicit

Private Sub cmdCleverButton_Click()
  MsgBox cmdCleverButton.Tag
End Sub

Private Sub Form_Load()
  modCleverButtonSublass.SubclassCleverButton cmdCleverButton, Me
End Sub

Private Sub Form_Unload(Cancel As Integer)
  modCleverButtonSublass.UnsubclassCleverButton
End Sub

模块 modCleverButtonSublass

Option Explicit

Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32.dll" 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 Const GWL_WNDPROC As Long = -4&
Private Const WM_SETFOCUS As Long = &H7&


Private m_PrevWndProc As Long
Private m_Button As CommandButton
Private m_Form As Form


Public Sub SubclassCleverButton(ByVal b As CommandButton, ByVal ParentForm As Form)
  If Not m_Button Is Nothing Then Err.Raise 5, , "Already subslassed."

  Set m_Button = b
  Set m_Form = ParentForm
  m_PrevWndProc = SetWindowLong(m_Button.hwnd, GWL_WNDPROC, AddressOf SubclassCallback)
End Sub

Public Sub UnsubclassCleverButton()
  If m_Button Is Nothing Then Err.Raise 5, , "Subclass first."

  SetWindowLong m_Button.hwnd, GWL_WNDPROC, m_PrevWndProc
  Set m_Form = Nothing
  Set m_Button = Nothing
End Sub


Private Function SubclassCallback(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  If uMsg = WM_SETFOCUS Then
    Dim c As Control

    Set c = FindByHwnd(m_Form, wParam)
    If c Is Nothing Then
      m_Button.Tag = vbNullString
    Else
      m_Button.Tag = c.Name
    End If
  End If

  SubclassCallback = CallWindowProc(m_PrevWndProc, hwnd, uMsg, wParam, lParam)
End Function

Private Function FindByHwnd(ByVal Parent As Form, ByVal hwnd As Long) As Control
  Dim c As Control

  For Each c In Parent.Controls
    If c.hwnd = hwnd Then
      Set FindByHwnd = c
      Exit Function
    End If
  Next
End Function

【讨论】:

  • 嗯,这段代码超出了我的想象。我只是一个做初学者项目的菜鸟,我正在学习在表单上添加按钮。有没有更简单的方法可以做到这一点?如果每个人都同意这是实现我想要的最简单的方法,我也会接受。
  • @phan 这取决于您如何定义“更简单”。这段代码实际上比为表单上的每个控件手动创建一个Lost_Focus() 处理程序更简单,您可以从中更新一个全局变量,以说明该控件是最后放弃其焦点的。也就是说,这段代码使用起来更简单,尽管它里面有更多的代码行,因为这些行你永远不需要更改。还有另一种解决方案,即添加对Microsoft Forms 2.0 Object Library 的引用,其中CommandButton 具有TakeFocusOnClick 属性。它甚至使用起来更简单,但在我看来它更像是一种矫枉过正。
  • 您好 GSerg,感谢您的 cmets。他们受到赞赏。我会让这个线程再逗留一点,如果没有其他人插话,我会接受你的回答。看,我当时想的是这个。使用计时器检查哪个控件每 1 秒具有焦点(设置 curControl = Screen.ActiveControl)。如果 curControl lastControl 则它将 lastControl 存储在一个变量中。无论如何,这是我的想法,让我看看我是否可以将其编码得更清楚。
【解决方案2】:
Private lastControl As Control
Private lastFocus As Control

Private Sub Timer1_Timer()

Dim curControl As Control
Set curControl = Screen.ActiveControl

If lastControl Is Nothing Then
    Set lastControl = curControl
End If

If curControl.Name <> lastControl.Name Then 
    Set lastFocus = lastControl  'this line memorizes which control most recently just had FOCUS
    Set lastControl = curControl
End If

End Sub

【讨论】:

    【解决方案3】:

    你需要一个简单的辅助焦点转发类来完成它,而不需要像这样的子类(不完整的示例类)

    ' cFocusFwd    
    Option Explicit
    
    Private WithEvents m_oCommand   As VB.CommandButton
    Private WithEvents m_oCombo     As VB.ComboBox
    Private WithEvents m_oText      As VB.TextBox
    Private WithEvents m_oCheck     As VB.CheckBox
    Private WithEvents m_oOption    As VB.OptionButton
    Private WithEvents m_oExt       As VB.VBControlExtender
    Private m_oForm                 As Object
    
    Friend Function frInit(oCtl As Object, oForm As Object) As Boolean
        If TypeOf oCtl Is VB.CommandButton Then
            Set m_oCommand = oCtl
        ElseIf TypeOf oCtl Is VB.ComboBox Then
            Set m_oCombo = oCtl
        ElseIf TypeOf oCtl Is VB.TextBox Then
            Set m_oText = oCtl
        ElseIf TypeOf oCtl Is VB.CheckBox Then
            Set m_oCheck = oCtl
        ElseIf TypeOf oCtl Is VB.OptionButton Then
            Set m_oOption = oCtl
        ElseIf TypeOf oCtl Is VB.VBControlExtender Then
            Set m_oExt = oCtl
        Else
            Exit Function
        End If
        Set m_oForm = oForm
        '--- success
        frInit = True
    End Function
    
    Private Sub m_oCommand_GotFocus()
        m_oForm.ControlGotFocus m_oCommand
    End Sub
    
    Private Sub m_oCombo_GotFocus()
        m_oForm.ControlGotFocus m_oCombo
    End Sub
    
    Private Sub m_oText_GotFocus()
        m_oForm.ControlGotFocus m_oText
    End Sub
    
    Private Sub m_oCheck_GotFocus()
        m_oForm.ControlGotFocus m_oCheck
    End Sub
    
    Private Sub m_oOption_GotFocus()
        m_oForm.ControlGotFocus m_oOption
    End Sub
    
    Private Sub m_oExt_GotFocus()
        m_oForm.ControlGotFocus m_oExt
    End Sub
    

    然后在您的表单中使用它来接收通知ControlGotFocus 回调子控件获得这样的焦点

    Option Explicit
    
    Private m_oLastFocused      As Object
    Private m_cFocusFwds        As Collection
    
    ' this is called from cFocusFwd when control gets focus
    Public Sub ControlGotFocus(oCtl As Object)
        If Not oCtl Is Command1 Then
            Set m_oLastFocused = oCtl
        End If
    End Sub
    
    Private Function pvInitFocusFwd(oCtl As Object, oForm As Object, Optional RetVal As cFocusFwd) As cFocusFwd
        Set RetVal = New cFocusFwd
        If RetVal.frInit(oCtl, oForm) Then
            Set pvInitFocusFwd = RetVal
        End If
    End Function
    
    Private Sub Form_Load()
        Dim oCtl        As Object
    
        Set m_cFocusFwds = New Collection
        For Each oCtl In Controls
            m_cFocusFwds.Add pvInitFocusFwd(oCtl, Me)
        Next
    End Sub
    
    Private Sub Command1_Click()
        MsgBox "Last active control is " & m_oLastFocused.Name, vbExclamation
    End Sub
    

    其中Command1 是处理m_oLastFocused 的命令按钮。

    不幸的是,这种方法在控制数组方面存在问题。子类化方法在获得焦点的无窗口控件方面存在问题。

    【讨论】:

      猜你喜欢
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      • 2023-03-24
      • 2020-05-29
      • 2013-07-22
      • 1970-01-01
      • 2012-07-14
      相关资源
      最近更新 更多