Home All Groups Group Topic Archive Search About

Close form if no user action including mouse move over form.

Author
5 Jun 2006 5:52 PM
Rob
This is a curious problem.  It seems like it should be quite easy.  Of course
a timer is used to determine when form should be closed, but how do you
consistently reset the timer when the mouse is moved over the form. 

Normally I would use the MouseMove event to know when the mouse moves over
the form and use that to reset the timer.  However, this fails on a form that
has a large number of controls of the form.  The Form.MouseMove event will
not fire when the pointer is over a control on the form!  Therefore in the
past I built recursive routine to go through the control collections of form
controls and recurse when a container is discovered in the controls
collection.  Then for each control found an handler is set for MouseMove to a
method that resets the timer and keeps the form open.

This works but it doesn't seem very graceful.  I was wondering if there is
more graceful way to do the same job.

Any help on this is appreciated.

Rob

Author
5 Jun 2006 10:09 PM
tommaso.gastaldi
Hi Rob,

see if this can be a way:

    Private WithEvents t As New Timer
    Private OldMousePos As Point

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        t.Interval = 100
        t.Start()
    End Sub

    Private Sub t_Tick(ByVal sender As Object, ByVal e As
System.EventArgs) Handles t.Tick
        If Not Me.Cursor.Position.Equals(OldMousePos) Then
Me.GlobalMouseMove(Me, EventArgs.Empty)
        Me.OldMousePos = Me.Cursor.Position
    End Sub

    'Here do your reset
    Sub GlobalMouseMove(ByVal sender As Object, ByVal EventArgs As
EventArgs)
        Me.Text = Cursor.Position.X.ToString & "," & _
        Cursor.Position.Y.ToString
    End Sub


Not sure it's really graceful.

-tom


Rob ha scritto:

Show quoteHide quote
> This is a curious problem.  It seems like it should be quite easy.  Of course
> a timer is used to determine when form should be closed, but how do you
> consistently reset the timer when the mouse is moved over the form.
>
> Normally I would use the MouseMove event to know when the mouse moves over
> the form and use that to reset the timer.  However, this fails on a form that
> has a large number of controls of the form.  The Form.MouseMove event will
> not fire when the pointer is over a control on the form!  Therefore in the
> past I built recursive routine to go through the control collections of form
> controls and recurse when a container is discovered in the controls
> collection.  Then for each control found an handler is set for MouseMove to a
> method that resets the timer and keeps the form open.
>
> This works but it doesn't seem very graceful.  I was wondering if there is
> more graceful way to do the same job.
>
> Any help on this is appreciated.
>
> Rob
Author
6 Jun 2006 6:06 AM
Cor Ligthert [MVP]
Yea,

Great (it is in my idea not complete, but the idea)
I was thinking about the hover event, but that would eat much processing.
Your sample does that not.
The only time it could go wrong is if the x and y would be the same; A
chance of 1 in a billion probably.

Cor

<tommaso.gasta***@uniroma1.it> schreef in bericht
Show quoteHide quote
news:1149545352.654411.280120@c74g2000cwc.googlegroups.com...
> Hi Rob,
>
> see if this can be a way:
>
>    Private WithEvents t As New Timer
>    Private OldMousePos As Point
>
>    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles MyBase.Load
>        t.Interval = 100
>        t.Start()
>    End Sub
>
>    Private Sub t_Tick(ByVal sender As Object, ByVal e As
> System.EventArgs) Handles t.Tick
>        If Not Me.Cursor.Position.Equals(OldMousePos) Then
> Me.GlobalMouseMove(Me, EventArgs.Empty)
>        Me.OldMousePos = Me.Cursor.Position
>    End Sub
>
>    'Here do your reset
>    Sub GlobalMouseMove(ByVal sender As Object, ByVal EventArgs As
> EventArgs)
>        Me.Text = Cursor.Position.X.ToString & "," & _
>        Cursor.Position.Y.ToString
>    End Sub
>
>
> Not sure it's really graceful.
>
> -tom
>
>
> Rob ha scritto:
>
>> This is a curious problem.  It seems like it should be quite easy.  Of
>> course
>> a timer is used to determine when form should be closed, but how do you
>> consistently reset the timer when the mouse is moved over the form.
>>
>> Normally I would use the MouseMove event to know when the mouse moves
>> over
>> the form and use that to reset the timer.  However, this fails on a form
>> that
>> has a large number of controls of the form.  The Form.MouseMove event
>> will
>> not fire when the pointer is over a control on the form!  Therefore in
>> the
>> past I built recursive routine to go through the control collections of
>> form
>> controls and recurse when a container is discovered in the controls
>> collection.  Then for each control found an handler is set for MouseMove
>> to a
>> method that resets the timer and keeps the form open.
>>
>> This works but it doesn't seem very graceful.  I was wondering if there
>> is
>> more graceful way to do the same job.
>>
>> Any help on this is appreciated.
>>
>> Rob
>
Author
6 Jun 2006 1:43 AM
gene kelley
On Mon, 5 Jun 2006 10:52:01 -0700, Rob <R**@discussions.microsoft.com>
wrote:

Show quoteHide quote
>This is a curious problem.  It seems like it should be quite easy.  Of course
>a timer is used to determine when form should be closed, but how do you
>consistently reset the timer when the mouse is moved over the form. 
>
>Normally I would use the MouseMove event to know when the mouse moves over
>the form and use that to reset the timer.  However, this fails on a form that
>has a large number of controls of the form.  The Form.MouseMove event will
>not fire when the pointer is over a control on the form!  Therefore in the
>past I built recursive routine to go through the control collections of form
>controls and recurse when a container is discovered in the controls
>collection.  Then for each control found an handler is set for MouseMove to a
>method that resets the timer and keeps the form open.
>
>This works but it doesn't seem very graceful.  I was wondering if there is
>more graceful way to do the same job.
>
>Any help on this is appreciated.
>
>Rob


(VB2005)

It's not clear if you are talking about a particular form in your app
or the app itself.  If the app, then you can use the Application.Idle
method which will fire when either a long process is complete or the
mouse is not moving - which ever occurs last. Scope of mouse move
detection in this method is application wide without regard to any
particular form or controls.

Gene
Author
6 Jun 2006 10:19 AM
tommaso.gastaldi
Good idea Gene,

.... but ... tried it and I must be missing something because does not
seem to work as we expect (?).

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        AddHandler Application.Idle, AddressOf TimeReset
    End Sub

    Sub TimeReset(ByVal sender As Object, ByVal e As System.EventArgs)
        MsgBox("Reset now")
    End Sub

Cor, to move the mouse returning exactly to the same start position
within 1/100th of a second would take an enormous speed and incredible
precision :)  Anyway your observation make me think about a situation
where the PC is a placed on a noisy place of work where there could be
"vibrations" which make move the mouse slightly. In such a case the
application is essentially idle, but since the vibrations make the
mouse move, it does not appear so. I would be interesting to study an
algorithm which redefines what "idle" means for noisy places !   :)





gene kelley ha scritto:

Show quoteHide quote
> On Mon, 5 Jun 2006 10:52:01 -0700, Rob <R**@discussions.microsoft.com>
> wrote:
>
> >This is a curious problem.  It seems like it should be quite easy.  Of course
> >a timer is used to determine when form should be closed, but how do you
> >consistently reset the timer when the mouse is moved over the form.
> >
> >Normally I would use the MouseMove event to know when the mouse moves over
> >the form and use that to reset the timer.  However, this fails on a form that
> >has a large number of controls of the form.  The Form.MouseMove event will
> >not fire when the pointer is over a control on the form!  Therefore in the
> >past I built recursive routine to go through the control collections of form
> >controls and recurse when a container is discovered in the controls
> >collection.  Then for each control found an handler is set for MouseMove to a
> >method that resets the timer and keeps the form open.
> >
> >This works but it doesn't seem very graceful.  I was wondering if there is
> >more graceful way to do the same job.
> >
> >Any help on this is appreciated.
> >
> >Rob
>
>
> (VB2005)
>
> It's not clear if you are talking about a particular form in your app
> or the app itself.  If the app, then you can use the Application.Idle
> method which will fire when either a long process is complete or the
> mouse is not moving - which ever occurs last. Scope of mouse move
> detection in this method is application wide without regard to any
> particular form or controls.
>
> Gene
Author
6 Jun 2006 8:58 PM
gene kelley
On 6 Jun 2006 03:19:10 -0700, tommaso.gasta***@uniroma1.it wrote:

Show quoteHide quote
>
>Good idea Gene,
>
>... but ... tried it and I must be missing something because does not
>seem to work as we expect (?).
>
>    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
>System.EventArgs) Handles MyBase.Load
>        AddHandler Application.Idle, AddressOf TimeReset
>    End Sub
>
>    Sub TimeReset(ByVal sender As Object, ByVal e As System.EventArgs)
>        MsgBox("Reset now")
>    End Sub
>
>

The above code in a simple app would result in a perpetual message box
and no way to exit the app. 

This simple example works here using a timer component.  If you simply
run the example, the message box displays after 5 seconds.  If you run
the example and move the mouse before 5 seconds has elapsed, the timer
restarts.

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        AddHandler Application.Idle, AddressOf TimeReset
        Me.Timer1.Interval = 5000

    End Sub


   Sub TimeReset(ByVal sender As Object, ByVal e As System.EventArgs)
        'Start/'Restart the timer
        Me.Timer1.Enabled = False
        Me.Timer1.Enabled = True

    End Sub

    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Timer1.Tick
        Me.Timer1.Enabled = False
        MessageBox.Show("App has been idle for 5 seconds. App
closing.")
        Me.Close()
    End Sub


Gene
Author
7 Jun 2006 10:20 AM
tommaso.gastaldi
Thank you Gene. Now I understand how the idle event works. Good to know
it. Thanks!

-tommaso

gene kelley ha scritto:

Show quoteHide quote
> On 6 Jun 2006 03:19:10 -0700, tommaso.gasta***@uniroma1.it wrote:
>
> >
> >Good idea Gene,
> >
> >... but ... tried it and I must be missing something because does not
> >seem to work as we expect (?).
> >
> >    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
> >System.EventArgs) Handles MyBase.Load
> >        AddHandler Application.Idle, AddressOf TimeReset
> >    End Sub
> >
> >    Sub TimeReset(ByVal sender As Object, ByVal e As System.EventArgs)
> >        MsgBox("Reset now")
> >    End Sub
> >
> >
>
> The above code in a simple app would result in a perpetual message box
> and no way to exit the app.
>
> This simple example works here using a timer component.  If you simply
> run the example, the message box displays after 5 seconds.  If you run
> the example and move the mouse before 5 seconds has elapsed, the timer
> restarts.
>
>    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles MyBase.Load
>         AddHandler Application.Idle, AddressOf TimeReset
>         Me.Timer1.Interval = 5000
>
>     End Sub
>
>
>    Sub TimeReset(ByVal sender As Object, ByVal e As System.EventArgs)
>         'Start/'Restart the timer
>         Me.Timer1.Enabled = False
>         Me.Timer1.Enabled = True
>
>     End Sub
>
>     Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As
> System.EventArgs) Handles Timer1.Tick
>         Me.Timer1.Enabled = False
>         MessageBox.Show("App has been idle for 5 seconds. App
> closing.")
>         Me.Close()
>     End Sub
>
>
> Gene