I have a form that consists of only a TableLayoutPanel (which fills the entire form) containing a vertical stack of buttons. The resulting app is used in conjunction with another app. What I would like is to have the vb app do something when the mouse enters the form. Unfortunately, all mouse enter/leave events are trapped by the panel or the buttons.

As a quick test I created a form with a tablelayoutpanel (docked to fill the form) containing one button. I added the following code:

Private Sub Form1_MouseEnter(sender As System.Object, e As System.EventArgs) Handles MyBase.MouseEnter
    Debug.WriteLine("enter form")
End Sub

Private Sub Form1_MouseLeave(sender As System.Object, e As System.EventArgs) Handles MyBase.MouseLeave
    Debug.WriteLine("leave form")
End Sub

Private Sub TableLayoutPanel1_MouseEnter(sender As System.Object, e As System.EventArgs) Handles TableLayoutPanel1.MouseEnter
    Debug.WriteLine("enter panel")
End Sub

Private Sub TableLayoutPanel1_MouseLeave(sender As System.Object, e As System.EventArgs) Handles TableLayoutPanel1.MouseLeave
    Debug.WriteLine("leave panel")
End Sub

Private Sub Button1_MouseEnter(sender As System.Object, e As System.EventArgs) Handles Button1.MouseEnter
    Debug.WriteLine("enter button")
End Sub

Private Sub Button1_MouseLeave(sender As System.Object, e As System.EventArgs) Handles Button1.MouseLeave
    Debug.WriteLine("leave button")
End Sub

There was no way of moving the mouse around that caused the form's mouse enter or leave events to fire. Is there anything (perhaps similar to KeyPreview) that lets me see the mouse enter/leave events at the form level? I could always add a common Mouse_Enter event to each button (all buttons are created at runtime) but this seems like a crude way to do it.

Hi Jim, I ran what you had set up in your test and tried TableLayoutPanel1.SendToBack and Me.BringToFront neither worked, Bummer.

Now for my question since you're getting the Panel MouseEnter event to fire isn't that the same as the Mouse entering the form or do you need the event Argument of the Form enter event. I’m just thinking out loud here.

I found this Click Here Might be a solution. I would just call the Forms mouse enter and leave subs from the Panels mouse enter and leave subs.

Hi Jim,

If I'm understanding your problem correctly, I think what you want is a message prefilter. These filters are added to the application and filter all application messages. By combining WM_MOUSEMOVE and WM_MOUSELEAVE with a hit test on the clientrectangle you can achieve this.

Public Class Form1
   Implements IMessageFilter
   Private Const WM_MOUSELEAVE As Int32 = &H2A3
   Private Const WM_MOUSEMOVE As Int32 = &H200
   Private MouseInForm As Boolean = False
   'Add a dock-filled panel to the form to block the normal MouseLeave, MouseEnter Events
   Private pnl As New Panel With {.Dock = DockStyle.Fill, .Parent = Me, .BorderStyle = BorderStyle.Fixed3D}

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      Application.AddMessageFilter(Me)
   End Sub


   Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
      If m.Msg = WM_MOUSELEAVE OrElse m.Msg = WM_MOUSEMOVE Then
         'hit test the client rectangle
         'since WM_MOUSELEAVE does not provide the mouse location, use MousePosition
         Dim hit As Boolean = Me.ClientRectangle.Contains(Me.PointToClient(MousePosition))
         If hit Then
            If Not MouseInForm Then
               OnMouseEnter(Nothing)
            End If
            MouseInForm = True
         Else
            If MouseInForm Then
               OnMouseLeave(Nothing)
            End If
            MouseInForm = False
         End If
      End If
   End Function

   Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
      Application.RemoveMessageFilter(Me)
   End Sub

   Private Sub Form1_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseEnter
      Debug.WriteLine("mouse entered form")
   End Sub

   Private Sub Form1_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
      Debug.WriteLine("mouse left form")
   End Sub
End Class

@Krod - Thanks for the suggestion but because the buttons completely fill the TableLayoutPanel, the panel never gets to trigger.

@TNTinMN - Also thanks. I think the prefilter is the way to go, however, I'll need to do a little research to figure out the finer points.

Looks like prefilter was the thing. As it turns out, I only really need to trap the mouse enter. Thanks again.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.