Joe 的 AutoRepeat Button 类的 .NET 移植






4.86/5 (32投票s)
这篇文档将 Joe Newcomer 的 AutoRepeat Button 类移植到 .NET 控件
引言
这是我尝试将 Joseph M Newcomer 的 AutoRepeat Button Class 移植到 .NET。我对此充满热情,尤其是我非常喜欢 Joe,而且我从未创建过自己的 .NET 控件。这实际上是我第一次尝试这样做。
控件
一个重复按钮就像这样,点击按钮后,如果持续按住,就会发生一些事情。例如,如果你有一个按钮,点击一下可以将某个值增加 1。然后如果你持续按住按钮,该值就会持续变化。就像你多次点击了该按钮一样。
就像 Joe 的按钮自动重复类一样,我的控件也只处理鼠标。如果你使用键盘点击按钮(使用 Enter 键),那么重复速率将是你的键盘的重复速率。这个功能在这个版本中被省略了,可能以后会添加。也许当 Joe 更新他的类时,我也会更新我的类。
该控件派生自 System.Windows.Forms.Button
类,因此在其他方面就像一个按钮。但是它有两个新的属性。 InitialDelay
和 RepeatDelay
,用于设置按钮开始自动重复之前的初始延迟和每次重复之间的重复延迟。
使用控件
好吧,如果你像我一样将它编译成一个 DLL,那么你可以将其添加为 .NET 控件。这意味着它会出现在你的工具箱中,你可以像添加任何其他控件一样添加它。你可以获取按钮的属性并设置 InitialDelay
和 RepeatDelay
属性。你不能将其设置为小于 100。所有单位均为毫秒。如果你想通过代码添加它,那么你可以像添加一个普通的 Button 控件一样添加它。
技术细节
就像 Joe 在他的类中做的那样,我使用了一个计时器。我有一个名为 m_timer
的私有 Timer
变量。我有两个名为 down
和 once
的 bool
变量。然后我还有两个用于初始延迟和重复延迟属性的私有变量。在构造函数中,我为 MouseUp
和 MouseDown
事件添加了处理程序。我还将一个函数与我的计时器关联起来。默认情况下,计时器是禁用的。
现在在我的 MouseDown
处理程序中,我做了三件事。我将 down
布尔变量设置为 true。我将计时器间隔设置为 InitialDelay
属性,然后我启用计时器。在我的 MouseUp
处理程序中,我只是禁用计时器,并将 down
设置为 false。最初我以为我必须捕获鼠标。因为用户可能会点击一个按钮,然后将鼠标拖出按钮并释放它。在普通的 win32 编程中,如果发生这种情况,你将不会收到鼠标抬起消息。但令我惊讶的是 [James Johnson 证实了这一点。我半夜叫醒他来确认这一点。可怜的 James!] 我发现即使鼠标在拖出后被释放,我们仍然会收到 MouseUp
事件处理程序被调用的事件。我想框架在内部为我们做了所有捕获的事情。
在我的计时器函数中,我首先将计时器间隔更改为 RepeatDelay
属性。现在我检查 down
变量是否为 true,这意味着鼠标按钮当前已按下。如果是按下状态,我使用 PerformClick
() 函数来模拟鼠标点击。我还将 once
布尔变量设置为 true
,就像 Joe 在他的类中所做的那样,尽管 Joe 实际上维护了已完成的重复次数计数,而不是使用布尔变量。我还重写了 OnClick
函数。如果 down
为 true
或者如果 once
变量为 false
,则调用基类,因为这表示重复未执行,就像快速鼠标点击时可能发生的那样。如果我不做这个 once
检查,我们最终总会多出一个重复,这是要避免的。
完整的源代码列表
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;
}
}
}
}
结论
你可以将此控件构建为类库,这使得使用它更容易,因为你可以使用表单设计器简单地将其拖放到表单中,你还可以使用 VS.NET 属性窗口设置属性。但是如果你不想这样做,你也可以将此类包含在你的项目中,然后手动将该控件添加到你的表单中。