按住鼠标按钮时C#如何循环

你能为我指出正确的方向吗? 我正试图在按下表单按钮时触发循环。

//pseudocode While (button1 is pressed) value1 += 1 

当然,当释放按钮时停止循环

为了避免使用线程,您可以在窗体/控件上添加一个Timer组件,只需在鼠标按下时启用它,并在鼠标向上禁用它。 然后将通常放在循环中的代码放入Timer_Tick事件中。 如果要使用System.Timers.Timer,则可以使用Timer.Elapsed事件。

示例(使用System.Timers.Timer):

 using Timer = System.Timers.Timer; using Systems.Timers; using System.Windows.Forms;//WinForms example private static Timer loopTimer; private Button formButton; public YourForm() { //loop timer loopTimer = new Timer(); loopTimer.Interval = 500;/interval in milliseconds loopTimer.Enabled = false; loopTimer.Elapsed += loopTimerEvent; loopTimer.AutoReset = true; //form button formButton.MouseDown += mouseDownEvent; formButton.MouseUp += mouseUpEvent; } private static void loopTimerEvent(Object source, ElapsedEventArgs e) { //do whatever you want to happen while clicking on the button } private static void mouseDownEvent(object sender, MouseEventArgs e) { loopTimer.Enabled = true; } private static void mouseUpEvent(object sender, MouseEventArgs e) { loopTimer.Enabled = false; } 

您可以使用线程进行计数,并在释放鼠标时停止线程。 以下对我有用:

 var b = new Button { Text = "Press me" }; int counter = 0; Thread countThread = null; bool stop = false; b.MouseDown += (s, e) => { stop = false; counter = 0; countThread = new Thread(() => { while (!stop) { counter++; Thread.Sleep(100); } }); countThread.Start(); }; b.MouseUp += (s, e) => { stop = true; countThread.Join(); MessageBox.Show(counter.ToString()); }; 

当然,如果您希望事件处理程序是方法而不是lambdas,则必须将所有变量都转换为字段。

  private void button1_MouseDown(object sender, MouseEventArgs e) { timer1.Enabled = true; timer1.Start(); } private void button1_MouseUp(object sender, MouseEventArgs e) { timer1.Stop(); } private void timer1_Tick(object sender, EventArgs e) { numericUpDown1.Value++; } 

来自Coding的Fabulous Adventures的最新文章提供了这种叙述,可能有助于回答您的问题:

令人惊讶的是,有很多人对应用程序如何响应Windows中的用户输入有着神奇的信念。 我向你保证,这不是魔术。 在Windows中构建交互式用户界面的方式非常简单。 当发生某些事情时,例如,鼠标单击按钮,操作系统会记下它。 在某些时候,一个进程要求操作系统“最近发生了什么有趣的事情?” 并且操作系统说“为什么是的,有人点击了这个东西。” 然后,该过程执行适合的任何操作。 发生了什么取决于这个过程; 它可以选择忽略点击,以自己特殊的方式处理它,或告诉操作系统“继续前进并做任何默认的事件。” 所有这些通常都是由您将看到的一些最简单的代码驱动的:

 while(GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } 

而已。 在具有UI线程的每个进程的核心位置都是一个看起来非常像这个循环的循环。 一个电话获得下一条消息。 这条消息可能对你来说太低了; 例如,它可能会说按下了具有特定键盘代码编号的键。 您可能希望将其翻译为“按下numlock键”。 TranslateMessage就是这么做的。 可能有一些更具体的程序来处理此消息。 DispatchMessage将消息传递给适当的过程。

我想强调一点,这不是魔术。 这是一个循环。 它在你见过的C中像C中的任何其他循环一样运行 。 循环重复调用三个方法,每个方法读取或写入一个缓冲区并在返回之前采取一些操作。 如果其中一个方法需要很长时间才能返回(通常DispatchMessage是长期运行的,因为它实际上是与消息相关的工作)那么猜猜是什么? UI不会从操作系统获取,转换或分派通知,直到它返回为止。

我的灵感来自于我在这里阅读的内容,并决定编写一个名为RepeatingButton的按钮类。 在第一次点击它等待500ms,然后重复300ms直到2s,然后每100ms重复一次(即它使用加速)。

这是代码;

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; ///  /// A repeating button class. /// When the mouse is held down on the button it will first wait for FirstDelay milliseconds, /// then press the button every LoSpeedWait milliseconds until LoHiChangeTime milliseconds, /// then press the button every HiSpeedWait milliseconds ///  public class RepeatingButton : Button { ///  /// Initializes a new instance of the  class. ///  public RepeatingButton() { internalTimer = new Timer(); internalTimer.Interval = FirstDelay; internalTimer.Tick += new EventHandler(internalTimer_Tick); this.MouseDown += new MouseEventHandler(RepeatingButton_MouseDown); this.MouseUp += new MouseEventHandler(RepeatingButton_MouseUp); } ///  /// The delay before first repeat in milliseconds ///  public int FirstDelay = 500; ///  /// The delay in milliseconds between repeats before LoHiChangeTime ///  public int LoSpeedWait = 300; ///  /// The delay in milliseconds between repeats after LoHiChangeTime ///  public int HiSpeedWait = 100; ///  /// The changeover time between slow repeats and fast repeats in milliseconds ///  public int LoHiChangeTime = 2000; private void RepeatingButton_MouseDown(object sender, MouseEventArgs e) { internalTimer.Tag = DateTime.Now; internalTimer.Start(); } private void RepeatingButton_MouseUp(object sender, MouseEventArgs e) { internalTimer.Stop(); internalTimer.Interval = FirstDelay; } private void internalTimer_Tick(object sender, EventArgs e) { this.OnClick(e); TimeSpan elapsed = DateTime.Now - ((DateTime)internalTimer.Tag); if (elapsed.TotalMilliseconds < LoHiChangeTime) { internalTimer.Interval = LoSpeedWait; } else { internalTimer.Interval = HiSpeedWait; } } private Timer internalTimer; } 

无论你有一个按钮,只需用一个重复按钮替换它,它就会内置所有新function。

请享用!

星级

覆盖表单中的OnMouseDown()方法,然后如果按下你想要的按钮,那将等于你的循环。 例:

 protected override void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { // this is your loop } } 

它不是传统意义上的循环,但应该适合您的需要。

您将需要处理表单的MouseDown()事件,使用MouseEventArgs参数来确定按下了哪个按钮。

我发布这个已经好几年了,但有人投了它,所以它在我的通知中弹出。 现在我有更多的经验大声笑,我想我会看到这个简单的问题是否像它听起来一样简单,它是:

 public partial class Form1 : Form { private bool _isRunning; public Form1() { InitializeComponent(); txtValue.Text = @"0"; btnTest.MouseDown += (sender, args) => { _isRunning = true; Run(); }; btnTest.MouseUp += (sender, args) => _isRunning = false; } private void Run() { Task.Run(() => { while (_isRunning) { var currentValue = long.Parse(txtValue.Text); currentValue++; txtValue.Invoke((MethodInvoker) delegate { txtValue.Text = currentValue.ToString(); }); } }); } } 

基于Steztric的答案,一种扩展方法,其中包含一些错误修复和不同的增加率选项。

 ///  /// An extension method to add a repeat click feature to a button. Clicking and holding on a button will cause it /// to repeatedly fire. This is useful for up-down spinner buttons. Typically the longer the mouse is held, the /// more quickly the click events are fired. There are different options when it comes to increasing the rate of /// clicks: /// 1) Exponential - this is the mode used in the NumericUpDown buttons. The first delay starts off around 650 ms /// and each successive delay is multiplied by 75% of the current delay. /// 2) Linear - the delay more slowly reaches the fastest repeat speed. Each successive delay subtracts a fixed /// amount from the current delay. Decreases in delays occur half a second apart. /// 3) Two Speed - this delay starts off at a slow speed, and then increases to a faster speed after a specified delay. /// 4) Three Speed - the repeat speed can increase from slow, to medium, to fastest after a specified delay. /// /// If repeating is added to a button that already has it, then it will be replaced with the new values. ///  public static class RepeatingButtonEx { private static Hashtable ht = new Hashtable(); private class Data { private static readonly System.Reflection.MethodInfo methodOnClick = null; static Data() { methodOnClick = typeof(Button).GetMethod("OnClick", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); } public Button Button = null; private Timer Timer = new Timer(); public double? GradientRate; public int? LinearGradient = null; public int FirstDelayMillis; public int FastestRepeatMillis; public int[] SwitchesMillis; public int[] SpeedsMillis; private DateTime lastEvent = DateTime.MinValue; private int millisCount = 0; private int currentSpeed = 0; private int waitSum = 0; public Data(Button button, double? gradientRate, int? linearGradient, int firstDelayMillis, int fastestRepeatMillis, int[] switchesMillis, int[] speedsMillis) { Button = button; GradientRate = gradientRate; LinearGradient = linearGradient; FirstDelayMillis = firstDelayMillis; FastestRepeatMillis = fastestRepeatMillis; SwitchesMillis = switchesMillis; SpeedsMillis = speedsMillis; Timer.Interval = firstDelayMillis; Timer.Tick += Timer_Tick; Button.MouseDown += Button_MouseDown; Button.MouseUp += Button_MouseUp; Button.MouseLeave += Button_MouseLeave; } void Button_MouseDown(object sender, MouseEventArgs e) { if (!Button.Enabled) return; lastEvent = DateTime.UtcNow; Timer.Start(); } void Button_MouseUp(object sender, MouseEventArgs e) { Reset(); } void Button_MouseLeave(object sender, EventArgs e) { Reset(); } private void Reset() { Timer.Stop(); Timer.Interval = FirstDelayMillis; millisCount = 0; currentSpeed = 0; waitSum = 0; } void Timer_Tick(object sender, EventArgs e) { if (!Button.Enabled) { Reset(); return; } methodOnClick.Invoke(Button, new Object[] { EventArgs.Empty }); //Button.PerformClick(); // if Button uses SetStyle(Selectable, false); then CanSelect is false, which prevents PerformClick from working. if (GradientRate.HasValue || LinearGradient.HasValue) { int millis = Timer.Interval; if (GradientRate.HasValue) millis = (int) Math.Round(GradientRate.Value * millis); else if (LinearGradient.HasValue) { DateTime now = DateTime.UtcNow; var ts = now - lastEvent; int ms = (int) ts.TotalMilliseconds; millisCount += ms; // only increase the rate every 500 milliseconds // otherwise it appears too get to the maximum rate too quickly if (millisCount >= 500) { millis -= LinearGradient.Value; millisCount -= 500; lastEvent = now; } } if (millis < FastestRepeatMillis) millis = FastestRepeatMillis; Timer.Interval = millis; } else { if (currentSpeed < SpeedsMillis.Length) { TimeSpan elapsed = DateTime.UtcNow - lastEvent; if (elapsed.TotalMilliseconds >= waitSum) { waitSum += SwitchesMillis[currentSpeed]; Timer.Interval = SpeedsMillis[currentSpeed]; currentSpeed++; } } } } public void Dispose() { Timer.Stop(); Timer.Dispose(); Button.MouseDown -= Button_MouseDown; Button.MouseUp -= Button_MouseUp; Button.MouseLeave -= Button_MouseLeave; } } ///The repeating speed becomes exponentially faster. This is the default behavior of the NumericUpDown control. ///The button to add the behavior. ///The delay before first repeat in milliseconds. ///The smallest delay allowed. Note: Masharling between the timer and the UI thread has an unavoidable limit of about 10 milliseconds. ///The new interval is the current interval multiplied by the gradient rate. public static void AddRepeatingExponential(this Button button, int firstDelayMillis = 500, int fastestRepeatMillis = 15, double gradientRate = 0.75) { AddRepeating(button, firstDelayMillis, fastestRepeatMillis, gradientRate, null, null, null); } ///The repeating speed becomes linearily faster. ///The button to add the behavior. ///The delay before first repeat in milliseconds. ///The smallest delay allowed. Note: Masharling between the timer and the UI thread has an unavoidable limit of about 10 milliseconds. ///If specified, the repeats gradually happen more quickly. The new interval is the current interval minus the linear gradient. public static void AddRepeatingLinear(this Button button, int firstDelayMillis = 500, int fastestRepeatMillis = 50, int linearGradient = 25) { AddRepeating(button, firstDelayMillis, fastestRepeatMillis, null, linearGradient, null, null); } ///The repeating speed switches from the slow speed to the fastest speed after the specified amount of milliseconds. ///The button to add the behavior. ///The delay before first repeat in milliseconds. ///The smallest delay allowed. Note: Masharling between the timer and the UI thread has an unavoidable limit of about 10 milliseconds. ///The delay in milliseconds between repeats when in the slow repeat state. ///The delay in milliseconds before switching from the slow repeat speed to the fastest repeat speed. public static void AddRepeatingTwoSpeed(this Button button, int firstDelayMillis = 500, int fastestRepeatMillis = 100, int slowRepeatMillis = 300, int slowToFastestSwitchMillis = 2000) { AddRepeating(button, firstDelayMillis, fastestRepeatMillis, null, null, new[] { slowRepeatMillis, fastestRepeatMillis }, new [] { slowToFastestSwitchMillis, 0 }); } ///The repeating speed switches from the slow to medium to fastest at speed switch interval specified. ///The button to add the behavior. ///The delay before first repeat in milliseconds. ///The smallest delay allowed. Note: Masharling between the timer and the UI thread has an unavoidable limit of about 10 milliseconds. ///The delay in milliseconds between repeats when in the slow repeat state. ///The delay in milliseconds between repeats when in the medium repeat state. ///The delay in milliseconds before switching from one speed state to the next speed state. public static void AddRepeatingThreeSpeed(this Button button, int firstDelayMillis = 500, int fastestRepeatMillis = 75, int slowRepeatMillis = 300, int mediumRepeatMillis = 150, int speedSwitchMillis = 2000) { AddRepeating(button, firstDelayMillis, fastestRepeatMillis, null, null, new[] { slowRepeatMillis, mediumRepeatMillis, fastestRepeatMillis }, new [] { speedSwitchMillis, speedSwitchMillis, 0 }); } private static void AddRepeating(this Button button, int firstDelayMillis, int fastestRepeatMillis, double? gradientRate, int? linearGradient, int[] speedsMillis, int[] switchesMillis) { Data d = (Data) ht[button]; if (d != null) RemoveRepeating(button); d = new Data(button, gradientRate, linearGradient, firstDelayMillis, fastestRepeatMillis, switchesMillis, speedsMillis); ht[button] = d; button.Disposed += delegate { RemoveRepeating(button); }; } ///Removes the repeating behavior from the button. public static void RemoveRepeating(this Button button) { Data d = (Data) ht[button]; if (d == null) return; ht.Remove(button); d.Dispose(); } } 

你可以使用mouseMove事件并检查鼠标按钮是否按下如下:

 private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if(e.Button==MouseButtons.Left) { //your code here } } 

RepeatButton非常适合:

  private void IncreaseButton_Click(object sender, RoutedEventArgs e) { value1++; }