Repeat-a-matic Mouse Button Problem

  • Thread starter Thread starter eBob.com
  • Start date Start date
E

eBob.com

I need a mouse button which does its thing when clicked, and keeps repeating
its thing when held down. I know that the code below is not very
sophisticated but I think that it is adequate for my immediate needs. The
problem is that when I depress and hold the mouse button down the button
does absolutely nothing. When clicked once it does what it should, i.e.
deletes the leftmost character. When clicked one and a half times, i.e.
clicked once and then immediately depressed and held, it goes into
repeat-a-matic mode. But I can't see why it is doing nothing when I depress
and hold it.

The code is dirt simple. I'd be very Thanksgiving if you'd look at it and
see if you can tell me what I am doing wrong.

Thanks, Bob

(btnLeftDel and TextBox1 are placed on a form using the designer.)
Option Strict On

Option Explicit On

Imports System.Threading

Public Class Form1

Dim LeftButtonDown As Boolean = False

Private Sub btnLeftDel_MouseDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles btnLeftDel.MouseDown

'remove leftmost character

Dim counter As Integer = 0

LeftButtonDown = True

Do While (TextBox1.Text.Length > 0) And _

(LeftButtonDown)

If counter = 0 Then

TextBox1.Text = TextBox1.Text.Substring(1)

'Application.DoEvents() 'doesn't help

End If

'counter += 1

Thread.Sleep(200)

Application.DoEvents() 'without this a single click always deletes 2
characters

'If counter = Form1.MouseBtnDownRepeatFactor Then counter = 0

Loop

End Sub



Private Sub btnLeftDel_MouseUp(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles btnLeftDel.MouseUp

LeftButtonDown = False

End Sub

End Class
 
First, get rid of DoEvents. It's nasty. ;)

I've used a Timer instead and it seems to work:

Private Sub Button1_MouseDown( _
ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles Button1.MouseDown

If e.Button = Windows.Forms.MouseButtons.Left Then
If TextBox1.Text.Length > 0 Then
Timer1.Start()
End If
End If

End Sub

Private Sub Timer1_Tick( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Timer1.Tick

Dim Text = TextBox1.Text

If Text.Length < 2 Then
Timer1.Stop()
End If

If Text.Length > 0 Then
TextBox1.Text = Text.Substring(1)
End If

End Sub

Private Sub Button1_MouseUp( _
ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles Button1.MouseUp

If e.Button = Windows.Forms.MouseButtons.Left Then
Timer1.Stop()
End If

End Sub
 
Thank you Armin. It's interesting to see a different approach.

But I'm embarassed to admit that this was a false alarm. Although I go back
and forth several times a day between a desktop with a mouse and a laptop
with a touch pad, I was not conscious of the difference between real mice
and my laptop's touch pad's simulation of a mouse.

On my laptop, to press and hold ANY button requires a double tap and hold,
whereas using the same laptop with a real mouse requires a single press and
hold of the mouse button.

When your code worked exactly like mine I thought maybe I should experiment
more with the touch pad and discovered my mistake. It's really strange, I
use my laptop A LOT and just wasn't conscious of what I was doing to cause
repeat-a-matic action.

By the way, what do you have against DoEvents?

Thanks again, Bob
 
eBob.com said:
Thank you Armin. It's interesting to see a different approach.

But I'm embarassed to admit that this was a false alarm. Although I go back
and forth several times a day between a desktop with a mouse and a laptop
with a touch pad, I was not conscious of the difference between real mice
and my laptop's touch pad's simulation of a mouse.

On my laptop, to press and hold ANY button requires a double tap and hold,
whereas using the same laptop with a real mouse requires a single press and
hold of the mouse button.

When your code worked exactly like mine I thought maybe I should experiment
more with the touch pad and discovered my mistake. It's really strange, I
use my laptop A LOT and just wasn't conscious of what I was doing to cause
repeat-a-matic action.

Thanks for the feedback.
By the way, what do you have against DoEvents?

If I want to do two things at a time, I use two threads. If there is already
one thread processing windows messages, why use DoEvents additionally? If messages
are not processed anymore, I look for the cause (that makes DoEvents necessary): The
cause is the loop inside the MouseDown event. If you remove it, the thread
keeps on doing what it is made for: processing messages.

Also, the UI thread should be as responsive as possible and consume as little
CPU power as possible. Your loop does not fulfil this as good as the (already
running) message loop does. It just (unnecessarily) occupies the CPU or,
using Thread.sleep, makes it less responsive. Moreove, any event handler should finish
as quickly as possible. If it's a long running task, it should be done in another
thread started in the event handler. That's not the case in your example, but
in your case it's just not necessary at all. It's like endlessly picking up
and hanging up the phone (because somebody might call) instead of
sitting there doing nothing and wait till it rings. ;)

In addition, DoEvents can cause code reentrance. Often, people are not aware
that everything can happen during DoEvents. For example, the Form can
be closed. Do you check if the Form is still visible after calling DoEvents?
If not, it can lead to exceptions because you assume it is still there.
In every event handler, are you aware that it might have been called during
DoEvents?

(BTW, there is still the bug that a button is clicked again even if you
click somewhere else on the form if the click is processed by calling Doevents.
Try it: put a button on a form. In it's click event, write a loop only
calling Doevents. Start. Click the button to make the loop run.
Then click on the [X] to close the Form. You see what I mean?)
 
Thanks Armin. All excellent points. I totallly agree.

Bob


Armin Zingler said:
eBob.com said:
Thank you Armin. It's interesting to see a different approach.

But I'm embarassed to admit that this was a false alarm. Although I go
back
and forth several times a day between a desktop with a mouse and a laptop
with a touch pad, I was not conscious of the difference between real mice
and my laptop's touch pad's simulation of a mouse.

On my laptop, to press and hold ANY button requires a double tap and
hold,
whereas using the same laptop with a real mouse requires a single press
and
hold of the mouse button.

When your code worked exactly like mine I thought maybe I should
experiment
more with the touch pad and discovered my mistake. It's really strange,
I
use my laptop A LOT and just wasn't conscious of what I was doing to
cause
repeat-a-matic action.

Thanks for the feedback.
By the way, what do you have against DoEvents?

If I want to do two things at a time, I use two threads. If there is
already
one thread processing windows messages, why use DoEvents additionally? If
messages
are not processed anymore, I look for the cause (that makes DoEvents
necessary): The
cause is the loop inside the MouseDown event. If you remove it, the thread
keeps on doing what it is made for: processing messages.

Also, the UI thread should be as responsive as possible and consume as
little
CPU power as possible. Your loop does not fulfil this as good as the
(already
running) message loop does. It just (unnecessarily) occupies the CPU or,
using Thread.sleep, makes it less responsive. Moreove, any event handler
should finish
as quickly as possible. If it's a long running task, it should be done in
another
thread started in the event handler. That's not the case in your example,
but
in your case it's just not necessary at all. It's like endlessly picking
up
and hanging up the phone (because somebody might call) instead of
sitting there doing nothing and wait till it rings. ;)

In addition, DoEvents can cause code reentrance. Often, people are not
aware
that everything can happen during DoEvents. For example, the Form can
be closed. Do you check if the Form is still visible after calling
DoEvents?
If not, it can lead to exceptions because you assume it is still there.
In every event handler, are you aware that it might have been called
during
DoEvents?

(BTW, there is still the bug that a button is clicked again even if you
click somewhere else on the form if the click is processed by calling
Doevents.
Try it: put a button on a form. In it's click event, write a loop only
calling Doevents. Start. Click the button to make the loop run.
Then click on the [X] to close the Form. You see what I mean?)
 
Back
Top