Reputation: 163
Trying to understand Timers and virtual clicks in C# Winforms. I want to have the program have an entered time value by the user (textbox1), then wait that amount of time and click the mouse, then increase the number counter (textbox2).
In the code below, the number counter immediately goes to 10, but the clicks are never ending, despite having a while loop set to stop the clicks at 10. I basically just want the program to wait a slightly random time (time entered to time entered +3), click the mouse, increase the counter, then pick a new random number and continue until 10 total clicks.
public Form1()
{
InitializeComponent();
}
private void NumbersOnly(object sender, KeyPressEventArgs e)
{
char ch = e.KeyChar;
if (!Char.IsDigit(ch) && ch != 8)
{
e.Handled = true;
}
}
static System.Timers.Timer _timer;
int numberofclicks = 0;
[DllImport("user32.dll")]
static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
private const int MOUSEEVENTF_MOVE = 0x0001;
private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
private const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
private const int MOUSEEVENTF_RIGHTUP = 0x0010;
private const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
private const int MOUSEEVENTF_MIDDLEUP = 0x0040;
private const int MOUSEEVENTF_ABSOLUTE = 0x8000;
private void StartClicked(object sender, EventArgs e)
{
numberofclicks = 0;
Random rsn = new Random();
while (numberofclicks < 10)
{
string startseconds = textBox1.Text;
int timerstartseconds = Convert.ToInt32(startseconds);
int timertime = rsn.Next(timerstartseconds * 1000, ((timerstartseconds + 3) * 1000));
_timer = new System.Timers.Timer(timertime);
_timer.Elapsed += _timer_Elapsed;
_timer.Enabled = true;
textBox2.Clear();
numberofclicks++;
string numbertextbox = numberofclicks.ToString();
textBox2.Text = numbertextbox;
}
}
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
LeftClick();
}
public static void LeftClick()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
}
Upvotes: 3
Views: 1170
Reputation: 10401
The problem lies in a fact that StartClicked
event handler does not block itself. It is just a simple method that without any delay loops 10 times changing the method level variable and modifying(even creating new!) Timer properties.
It is possible to do what you attempted to do in such a manner(single method with simple loop), but you will have to use async event handler and will have no need for a timer. And as the another answer already discusses how to do it with classic timers, I will give you such async-based solution:
private async void StartClicked(object sender, EventArgs e)
{
numberofclicks = 0;
Random rsn = new Random();
while (numberofclicks < 10)
{
string startseconds = textBox1.Text;
int timerstartseconds = Convert.ToInt32(startseconds);
int timertime = rsn.Next(timerstartseconds * 1000, ((timerstartseconds + 3) * 1000));
await Task.Delay(timertime);
LeftClick();
textBox2.Clear();
numberofclicks++;
string numbertextbox = numberofclicks.ToString();
textBox2.Text = numbertextbox;
}
}
For more information on async-await you can read MSDN on async-await.
Upvotes: 2
Reputation: 103437
When you say _timer.Enabled = true;
, the rest of your code keeps executing. Then at some time later, when the timer ticks, the Elapsed
event is triggered.
Additionally, each timer you create keeps on ticking - they don't only fire once.
Also, there are many different Timer classes in the .NET framework. For a simple winforms app like yours, I would stick with the System.Windows.Forms.Timer
version. You don't have to worry about threading and such that way.
You might be better served with something like this:
private Random rsn = new Random();
private int numberofclicks = 0;
private System.Windows.Forms.Timer _timer;
// set the timer's tick event handler in form_load or similar.
// you could also just drag a timer onto the form and double-click it.
private void StartClicked(object sender, EventArgs e)
{
// don't allow starting again until finished
btnStart.Enabled = false;
numberofclicks = 0;
_timer.Interval = /* get randomish interval */
_timer.Start();
}
void _timer_Tick(object sender, EventArgs e)
{
_timer.Stop();
LeftClick();
numberofclicks++;
if (numberofclicks >= 10) {
btnStart.Enabled = true;
}
else {
_timer.Interval = /* get randomish interval */
_timer.Start();
}
}
Upvotes: 2