Solved

VB .NET: using onMouseLeave on form

Posted on 2004-11-01
269 Views
Last Modified: 2010-04-24
I'm creating a form that expands, and when the user moves the mouse off the expanded form, I want to trigger the resize to normal. It also seems that if the mouse enters a control on the form it triggers the form's onMouseleave event.

I am setting the size by: me.height = 100

But the onMouseleave event seems to fire when the mouse moves onto a control, or moves past the OLD size of the form.

How can I get the onMouseleave event not to fire if i move into a control it owns, and to use the form's new size when calculating if the user has moved the mouse out of it?

Is this a good approach: when the form's onMouseLeave event is triggered determine if the mouse is in the border of the form? How would I do that?

Thanks!
0
Question by:majnun
    19 Comments
     
    LVL 4

    Expert Comment

    by:andrewharris
    I would use the fors LostFocus Event instead.

    Andrew
    0
     

    Author Comment

    by:majnun
    Yeah, but the expanded form might be covering up the other windows, so it's better to use a modified "mouseOut" functionality so that the user can actually click the other forms to change the focus.

    I'm working on figuring out how to check the mouse position against the actual boundaries of the form.
    0
     
    LVL 8

    Expert Comment

    by:toddhd
       Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
            If (e.X > 0 And e.X < Me.Width) And (e.Y > 0 And e.Y < Me.Height) Then
                Me.Width = 400
                Me.Height = 400
            Else
                Me.Width = 300
                Me.Height = 300
            End If
        End Sub
    0
     
    LVL 8

    Expert Comment

    by:toddhd
    Sorry, change the form values to whatever you want - but you get the idea
    0
     

    Author Comment

    by:majnun
    toddhd:

    on the right track, but the problem is that it only shrinks when i move the mouse out slowly to the left... if i move out quickly or exit the form rectangle in any other direction it stays at the bigger dimensions.

    0
     
    LVL 8

    Expert Comment

    by:toddhd
    I'll keep thinking - in the meantime, if it's not a high-perf app, you can add a loop or timer somewhere to call OnMouseMove on a given interval - say, every one second. That might help. Better yet, skip the event altogether and just track the mouse in a loop (I'm old an school game programmer - that's how I'd do it anyway).

    Just FYI - I'm not having that problem on my machine - even fast, it's working.
    0
     

    Author Comment

    by:majnun
    Ok here's what i did and it works (add to the forms onMouseLeave event):

      Dim X, Y, Xoffset, Yoffset, Mx, My As Integer
            Dim off As Boolean = False
            Xoffset = 5 'border pixels
            Yoffset = 35 'titlebar & border pixels

            X = Me.Width - Xoffset
            Y = Me.Height - Yoffset
            Mx = Me.PointToClient(Me.MousePosition).X
            My = Me.PointToClient(Me.MousePosition).Y
         
            If Mx >= X Or Mx < 1 Then off = True
            If My >= Y Or My < 1 Then off = True

            If off then 'shrink window

    Can someone help me refine this so that it automatically takes the title bar and form border into consideration, so that i can use the same function for different form types (with and without title bars, dialogs, etc. etc.) and at different screen resolutions (becase as it stands i think the offsets will need to change based on the screen resolution, no?)

    If anyone has a better way of doing this please let me know.
    0
     

    Author Comment

    by:majnun
    I like toddhd solution of overriding the onMouseMove sub better than mine, seems more efficient... i wonder why i cant get it to work properly... any thoughts?
    0
     
    LVL 1

    Expert Comment

    by:hagipmc
    majnun ,
    check out bounds property!
    from msdn:
    "
    .NET Framework Class Library  

    Control.Bounds Property
    Gets or sets the size and location of the control including its nonclient elements.

    [Visual Basic]
    Public Property Bounds As Rectangle
    [C#]
    public Rectangle Bounds {get; set;}
    [C++]
    public: __property Rectangle get_Bounds();
    public: __property void set_Bounds(Rectangle);
    [JScript]
    public function get Bounds() : Rectangle;
    public function set Bounds(Rectangle);
    Property Value
    A Rectangle that represents the size and location of the control including its nonclient elements.

    Remarks
    The bounds of the control includes the nonclient elements such as scroll bars, borders, title bars, and menus. The SetBoundsCore method is called to set the Bounds property. The Bounds property is not always changed through its set method so you should override the SetBoundsCore method to ensure that your code is executed when the Bounds property is set.
    "
    0
     
    LVL 8

    Expert Comment

    by:toddhd
    Majnun,

    FYI again, I think I just "lucked out" last night - I tried it again this morning, and it's not working so well - I'm still working on it when I can... just wanted to let you know "it's not you" :)
    0
     
    LVL 8

    Expert Comment

    by:toddhd
    Ok, try this:

        Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
            Me.Width = 400
            Me.Height = 400
        End Sub

        Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
            Dim Flag As Boolean = False
            Dim c As Control
            For Each c In Me.Controls
                Dim p As Point
                p = Me.PointToClient(Me.MousePosition)
                If p.X >= c.Left And p.X <= c.Left + c.Width Then
                    If p.Y >= c.Top And p.Y <= c.Top + c.Height Then
                        Flag = True
                    End If
                End If
            Next

            If Not Flag Then
                Me.Width = 300
                Me.Height = 300
            End If

        End Sub
    0
     

    Author Comment

    by:majnun
    hagipmc:

    Interesting, might be very helpful, but two problems I am having with it though:

    1) It doesn't seem to do the trick because:

    MsgBox(Me.Bounds.Height & " | " & Me.Height)

    Me.Bounds.Height returns the same int as Me.Height

    2) If I can get the Bounds to represent the form plus titlebar, borders, etc. when does the onMouseLeave fire? When the mouse moves out of the bounds or out of the area of the form inside the bounds?

    0
     

    Author Comment

    by:majnun
    Ok this works almost perfectly (in the form's onMouseLeave):

        Dim X, Y, Xoffset, Yoffset, Mx, My As Integer
            Dim off As Boolean = False

            X = Me.ClientSize.Width
            Y = Me.ClientSize.Height

            Mx = Me.PointToClient(Me.MousePosition).X
            My = Me.PointToClient(Me.MousePosition).Y

            If Mx >= X Or Mx < 1 Then off = True
            If My >= Y Or My < 1 Then off = True

            If off Then popBack() 'resize


    I say it works almost perfectly, because if I move the mouse out really fast it doesn't seem to trigger the onMouseLeave event... i'm assuming because the mouse position "jumps" over the boundary of the client area of the form and so never triggers the onMouseLeave event.
    0
     

    Author Comment

    by:majnun
    Woops, don't need the  Xoffset, Yoffset dimmed in the above.
    0
     

    Author Comment

    by:majnun
    ok, last thing to do i think is trigger the onMouseLeave event for the form on the onMouseEnter sub of the owning form... anyone know how I can trigger one form's events from another form?

    Thanks!
    0
     

    Author Comment

    by:majnun
    ok, on second thought, incase i want to use this for non-owned forms, maybe i'll start a timer when the form is expanded and poll the mouse position every few seconds incase i moved off to fast, then destroy the timer when the form shrinks.
    0
     

    Author Comment

    by:majnun
    Ok, i've figured out a solution which works for me, and in case others find the particular execution useful here's the entirety:
    In plain english:
    The form (mediaPlayer) has a bunch of controls, one of the controls is a panel (pnlPlaylist) which is "hidden" below the forms border (i size the control so that the panel is not visible, but sits hidden "below" everything else). This panel is revealed when the form pops (expands and reveals the hidden panel). Based on the position of the form in relation to its parent form, it either pops up or pops down. If the form pops down the size increases and reveals the panel, if the form pops up the size increases, the panel jumps to the top of the form, and the other controls are repositioned to the bottom appropriately. I create an arraylist which holds control names which need to be repositioned to the bottom of the form when the form pops down (note i exclude the panel since it is positioned explicity). When the mouse moves out of the form its checks to make sure the mouse position is actually outside the form and then pops back to the smaller position. Just incase the user moves the mouse out to fast, a timer is created and started when the form pops bigger and poles the mouse position every two seconds and closes it if the mouse is off the form (the timer is also disposed whenever the form shrinks),

    In code:
        Dim popHeight As Integer = 200
        Dim poppedDown As Boolean = False
        Dim poppedUp As Boolean = False
        Dim alControls As New ArrayList()
        Dim intPnlPlaylistTop As Integer
        Dim WithEvents tmrPop As System.Timers.Timer

        Sub tmrPop_Elapsed(ByVal sender As Object, _
                                ByVal e As System.Timers.ElapsedEventArgs) _
                                Handles tmrPop.Elapsed
            ' Respond to event
            popBack()
        End Sub

        Sub pop()
            If Me.Height < popHeight Then
                tmrPop = New System.Timers.Timer()
                tmrPop.Interval = 2000
                tmrPop.Start()
                If Me.Top < (Me.ParentForm.Size.Height / 2) Then
                    popDown()
                Else
                    popUp()
                End If
            End If
        End Sub

        Sub popDown()
            Me.Height = Me.Height + popHeight
            poppedDown = True
        End Sub

        Sub popUp()
            Dim ctr As Control
            Me.Height = Me.Height + popHeight
            For Each ctr In alControls
                ctr.Top = ctr.Top + popHeight
            Next
            intPnlPlaylistTop = pnlPlaylist.Top
            pnlPlaylist.Top = 10 'can't be at 0 because i need to pass over the form on the way out to trigger the onMouseLeave event
            Me.Top = Me.Top - popHeight
            poppedUp = True
        End Sub

        Sub popBack()
            Dim X, Y, Mx, My As Integer
            Dim off As Boolean = False

            X = Me.ClientSize.Width
            Y = Me.ClientSize.Height

            Mx = Me.PointToClient(Me.MousePosition).X
            My = Me.PointToClient(Me.MousePosition).Y

            If Mx >= X Or Mx < 1 Then off = True
            If My >= Y Or My < 1 Then off = True

            If off Then
                If poppedUp Or poppedDown Then
                    tmrPop.Dispose()
                End If

                If poppedDown = True Then
                    Me.Height = Me.Height - popHeight
                    poppedDown = False
                End If

                If poppedUp = True Then
                    Dim ctr As Control
                    Me.Height = Me.Height - popHeight
                    For Each ctr In alControls
                        ctr.Top = ctr.Top - popHeight
                    Next
                    pnlPlaylist.Top = intPnlPlaylistTop
                    Me.Top = Me.Top + popHeight
                    poppedUp = False
                End If

            End If
        End Sub

        Private Sub MediaPlayer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            'add all the controls to the alControls arraylist
            'use a case to check for control names not to add to arraylist
            Dim ctr As Control
            For Each ctr In Me.Controls
                Select Case ctr.Name
                    Case "pnlPlaylist" 'controlName, controlName, etc. for controls not to add to the alControls arraylist
                    Case Else
                        alControls.Add(ctr)
                End Select
            Next

        End Sub

        Private Sub lblPlaylist_MouseHover(ByVal sender As Object, ByVal e As System.EventArgs) Handles lblPlaylist.MouseHover
            pop()
        End Sub

        Public Sub MediaPlayer_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.MouseLeave
            popBack()
        End Sub



    I will leave this thread open for awhile to see if anyone has come up with a more elegant solution, or has suggestions regarding this implementation.

    Thanks!
    0
     

    Author Comment

    by:majnun
    MODERATOR:

    Is it possible to change the title of the question to:
    "Expanding/Contracting forms: onMouseOut problem"

    Since i've included the whole solution in case someone is wondering how to do it?
    0
     

    Accepted Solution

    by:
    PAQed with points refunded (500)

    modulo
    Community Support Moderator
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone. Privacy Policy Terms of Use

    Featured Post

    Top 6 Sources for Identifying Threat Actor TTPs

    Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

    I'm currently working for a company where I have to upgrade over 50 VB6 programs to VB.NET 2008.  So far I'm about half way through, and I've learned quite a few tricks that drastically improve the performance of VB.NET apps. Because there are a…
    Article by: Kraeven
    Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
    In this Experts Exchange video Micro Tutorial, I'm going to show how small business owners who use Google Apps can save money by setting up what is called a catch-all email address in their Gmail accounts. By using the catch-all feature, small busin…
    In this sixth video of the Xpdf series, we discuss and demonstrate the PDFtoPNG utility, which converts a multi-page PDF file to separate color, grayscale, or monochrome PNG files, creating one PNG file for each page in the PDF. It does this via a c…

    860 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    14 Experts available now in Live!

    Get 1:1 Help Now