Introduction
This is my attempt at porting Joseph M Newcomer's AutoRepeat Button Class to .NET. I was quite enthusiastic
about doing this specially since I am a big fan of Joe and also because I had
never created a .NET control of my own. This is actually my first crack at doing
this.
The Control
Well a repeat button is a button on which you can click and then when you
keep it clicked something happens. For instance, if you have a button that
you click to increase some value by 1. Then if you keep the button clicked, the
value keeps changing. As if you had clicked on the button multiple times.
Just as in Joe's button auto-repeat class, my control also only handles the
mouse. If you use the keyboard to click on a button (by using the ENTER key),
then the repeat rate will be that of your keyboard. This has been left out in
this version and might be a feature for later. Maybe when Joe updates his class,
I'll update mine as well.
The control was derived from the System.Windows.Forms.Button
class and thus acts as a button in every other way. It has two new properties
though. InitialDelay
and RepeatDelay
which are used to
set the initial delay before the button starts auto-repeating and the repeat
delay between each repeat.
Using the control
Well, if you compile it as a DLL like I did, then you can add it as a .NET
control. Which means you'll have it on your toolbox and you can add it just as
you'd add any other control. You can take the button's properties and set the
InitialDelay
and RepeatDelay
property. You cannot set
it to less than 100. All units are in milliseconds. If you want to add it via
code then you can add it just as you would add a normal Button control.
Tech Details
Just as Joe did in his class, I use a timer. I have a private
Timer
variable called m_timer
. I have two
bool
variables called down
and once
. Then
I also have two private variables for the initial delay and repeat delay
properties. In the constructor I add handlers for the MouseUp
and
MouseDown
events. I also associate a function with my timer. By
default the timer is disabled.
Now in my MouseDown
handler I do three things. I set the
down
boolean variable to true. I set the timer interval to the
InitialDelay
property and then I enable the timer. In my
MouseUp
handler I simply disable the timer and also make
down
false. Initially I thought I'd have to capture the mouse too.
Because the user might click on a button and then drag the mouse out of the
button and release it. In normal win32 programming you won't get the mouse up
messages if this happens. But to my surprise [James Johnson has confirmed this.
I woke him up in the middle of the night to get this confirmed. Poor James!] I
found that even if the mouse is released after being dragged out, we still get
the MouseUp
event handler called. I guess the framework internally
does all the capturing stuff for us.
In my timer function, I first change the timer interval to the
RepeatDelay
property. Now I check if the down
variable
is true which means that the mouse button is currently down. And if it is down,
I use the PerformClick
() function to simulate a mouse click. I also
set the once
boolean variable to true
just as Joe does
in his class, though instead of a boolean variable, Joe actually maintains a
count of the number of repeats completed. I also override the
OnClick
function. I call the base class if either down
is true
or if the once
variable is false
,
because that indicates that the repeats were not performed as could happen with
a quick mouse click. If I didn't do this once
check, we'd always
end up with one extra repeat which is to be avoided.
Complete source listing
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
namespace RepeatButton
{
public class RepeatButton : System.Windows.Forms.Button
{
private Timer m_timer;
private bool down=false;
private bool once=false;
private int m_initdelay=1000;
private int m_repdelay=400;
public RepeatButton()
{
this.MouseUp +=
new MouseEventHandler(RepeatButton_MouseUp);
this.MouseDown +=
new MouseEventHandler(RepeatButton_MouseDown);
m_timer = new Timer();
m_timer.Tick += new EventHandler(timerproc);
m_timer.Enabled=false;
}
private void timerproc(object o1, EventArgs e1)
{
m_timer.Interval = m_repdelay;
if(down)
{
once=true;
this.PerformClick();
}
}
protected override void OnClick(EventArgs e)
{
if(!once || down)
base.OnClick(e);
}
private void RepeatButton_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
m_timer.Interval=m_initdelay;
m_timer.Enabled=true;
down=true;
}
private void RepeatButton_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
m_timer.Enabled=false;
down=false;
}
public int InitialDelay
{
get
{
return m_initdelay;
}
set
{
m_initdelay = value;
if(m_initdelay<100)
m_initdelay=100;
}
}
public int RepeatDelay
{
get
{
return m_repdelay;
}
set
{
m_repdelay = value;
if(m_repdelay<100)
m_repdelay=100;
}
}
}
}
Conclusion
You may build this control as a class library which makes it easier to use
it, because you can simply drag/drop it into a form using the form designer and
you can also set properties using VS.NET properties window. But if you don't
want to do that, you may also include this class in your project and manually
add the control to your form.