你能给我指点方向吗?我正在尝试在表单按钮按下时触发循环。
//pseudocode
While (button1 is pressed)
value1 += 1
当然,在释放按钮时停止循环
你能给我指点方向吗?我正在尝试在表单按钮按下时触发循环。
//pseudocode
While (button1 is pressed)
value1 += 1
当然,在释放按钮时停止循环
为了避免使用线程,您可以在表单/控件上添加一个计时器组件,并在鼠标按下时启用它,在鼠标松开时禁用它。然后将通常放置在循环中的代码放在计时器的Tick事件中。如果您想使用System.Timers.Timer,则可以使用Timer.Elapsed事件代替。
示例(使用System.Timers.Timer):
using Timer = System.Timers.Timer;
using System.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)
{
//this does 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;
}
(e.Button == MouseButtons.Left)
,否则你最终会在LeftClick、RightClick、MiddleClick或其他任何鼠标按钮上执行循环。通常情况下,按钮应该只响应左键单击。 - abelenkyTimer
的问题在于它不够准确,这是众所周知的。尝试将计时器设置为已知的毫秒 间隔
,然后计算计时器的 ticks
数量并将其与秒表的 elapsed_milliseconds/interval
进行比较。你会发现得到的值有明显的差异。但如果 OP 不需要高精度,这是一个不错的解决方案。 - Gondil您可以使用线程来进行计数,并在鼠标释放时停止线程。以下对我非常有效:
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());
};
当然,如果你想要事件处理程序成为方法而不是lambda表达式,你将不得不把所有变量转换为字段。
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++;
}
我受到这里阅读的启发,决定编写自己的按钮类,称为“重复按钮”。第一次单击后,它会等待500毫秒,然后每300毫秒重复一次,直到2秒钟,然后每100毫秒重复一次(即使用加速度)。
以下是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
/// <summary>
/// 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
/// </summary>
public class RepeatingButton : Button
{
/// <summary>
/// Initializes a new instance of the <see cref="RepeatingButton"/> class.
/// </summary>
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);
}
/// <summary>
/// The delay before first repeat in milliseconds
/// </summary>
public int FirstDelay = 500;
/// <summary>
/// The delay in milliseconds between repeats before LoHiChangeTime
/// </summary>
public int LoSpeedWait = 300;
/// <summary>
/// The delay in milliseconds between repeats after LoHiChangeTime
/// </summary>
public int HiSpeedWait = 100;
/// <summary>
/// The changeover time between slow repeats and fast repeats in milliseconds
/// </summary>
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;
}
无论何处你有一个按钮,你只需要用重复按钮替换它,就可以拥有所有新功能。
享受吧!
Sterren
Fabulous Adventures in Coding的最新文章提供了以下叙述,可能有助于回答你的问题:
A surprising number of people have magical beliefs about how exactly applications respond to user inputs in Windows. I assure you that it is not magic. The way that interactive user interfaces are built in Windows is quite straightforward. When something happens, say, a mouse click on a button, the operating system makes a note of it. At some point, a process asks the operating system "did anything interesting happen recently?" and the operating system says "why yes, someone clicked this thing." The process then does whatever action is appropriate for that. What happens is up to the process; it can choose to ignore the click, handle it in its own special way, or tell the operating system "go ahead and do whatever the default is for that kind of event." All this is typically driven by some of the simplest code you'll ever see:
while(GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); }
That's it. Somewhere in the heart of every process that has a UI thread is a loop that looks remarkably like this one. One call gets the next message. That message might be at too low a level for you; for example, it might say that a key with a particular keyboard code number was pressed. You might want that translated into "the numlock key was pressed". TranslateMessage does that. There might be some more specific procedure that deals with this message. DispatchMessage passes the message along to the appropriate procedure.
I want to emphasize that this is not magic. It's a while loop. It runs like any other while loop in C that you've ever seen. The loop repeatedly calls three methods, each of which reads or writes a buffer and takes some action before returning. If one of those methods takes a long time to return (typically DispatchMessage is the long-running one of course since it is the one actually doing the work associated with the message) then guess what? The UI doesn't fetch, translate or dispatch notifications from the operating system until such a time as it does return.
在您的表单中覆盖OnMouseDown()
方法,然后如果按下所需按钮,这将等于您的循环。示例:
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// this is your loop
}
}
这不是传统意义上的循环,但应该能满足你的需求。
RepeatButton非常适合这种情况:
"<RepeatButton Delay="1000" Interval="500" HorizontalAlignment="Left" Content="+" Click="IncreaseButton_Click"/>
private void IncreaseButton_Click(object sender, RoutedEventArgs e)
{
value1++;
}
我发布这篇文章已经过去了几年,但有人点赞了它,所以它出现在了我的通知中。现在我有更多的经验了,哈哈,我想看看这个简单的问题是否像听起来那么简单,结果是:
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();
});
}
});
}
}
MouseDown()
事件,使用MouseEventArgs
参数来确定按下了哪个按钮。private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if(e.Button==MouseButtons.Left)
{
//your code here
}
}
e
不会在方法内改变。 - NappingRabbit