My program binds "Z" key to a handler that activates a timer.
That timer triggers a mouse click.
Problem is that if I keep Z pressed more than 5 seconds, it gets stuck and on KeyUp it doesn't fire, variable doesn't change to false and loop is endless, so it continues firing timer's callback when key is not pressed anymore. Only way to stop it is via ALT+F4
My code is at http://pastebin.com/rbCgY1rb
I use globalKeyboardHook from here
Critical part of code is:
private void keyDownCallback(object sender, KeyEventArgs e) {
if (e.KeyCode.ToString() == "Z") {
timer1.Enabled = true;
this.forceNoLoop = false;
} else if(e.KeyCode.ToString() == "X") {
timer1.Enabled = false;
this.forceNoLoop = true;
}
}
private void keyUpCallback(object sender, KeyEventArgs e) {
timer1.Enabled = false;
this.forceNoLoop = true;
}
private void timer1_Tick(object sender, EventArgs e) {
if (forceNoLoop) return;
mouse_event(MOUSEEVENTF_LEFTDOWN, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
lblClickStatus.Text = "clicked " + (this.clickTimes++) + " times";
}
So question is: how to fix the freeze problem?
Can you try checking the state of the timer before enabling/disabling it?
private void keyDownCallback(object sender, KeyEventArgs e) {
if (e.KeyCode.ToString() == "Z") {
if (!timer1.Enabled)
timer1.Enabled = true;
} else if (e.KeyCode.ToString() == "X") {
if (timer1.Enabled)
timer1.Enabled = false;
}
}
Related
Can someone tell me why this do not work?
i want to start a Thread by pressing a key and stops automatically, then he have to make a rest and starts again.
But if i pressing this key then nothing happens.
he have to start void StartFunction, but Thread isnt starting. If i start the Thread on Forms_load then is all fine. but i need this Thread only on pressing a key
private void StartFunction()
{
Thread AB = new Thread(SEARCHING) { IsBackground = true };
AB.Start();
}
private void StopFunction()
{
Thread AB = new Thread(SEARCHING) { IsBackground = true };
AB.Abort();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.L)
{
StartFunction();
MessageBox.Show("Timer 1 started!");
}
}
int time = 10;
private void timer1_Tick(object sender, EventArgs e)
{
time++;
if (time == 2 && timer1.Enabled)
{
timer1.Stop();
time = 0;
StopFunction();
}
if (time == 2 && !timer1.Enabled)
{
timer1.Start();
time = 0;
StartFunction();
MessageBox.Show("Timer 1 started!");
}
}
You could make it easier for yourself by storing the timer_tick in a variable.
When the variable has reached 120(2 min) stop the timer. First you should start the timer and then:
private void timer1_Tick(object sender, EventArgs e)
{
time++;
if(time == 120 && timer1.Enabled)
{
timer1.Stop();
time = 0;
}
if(time == 60 && !timer1.Enabled){
timer1.Start();
time = 0;
}
}
You can find the timer_tick event at the ptoperties of the timer.
Im making a program, whenever it receives message "000000000", it will draw the graph.i try using Timer. I start Timer in Form_Load event. When it receive message "0000000"(in other Thread), i enable the timer :timer1.Enabled = true; . It works but it always draw and redraw the graph, never stop, i try to disable the timer after 1st time it finishes drawing. But when i disable the timer: timer1.Enabled =false;, it draws for the 1st time and then i receive the "0000000" message one more time(), it did not draw any more. I want it to draw only 1 time whenever it receives the "0000000" message. Please help me. Here is my code.
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
I start the timer on Form_Load.
if (cnvertMsg == "0000000000000000" || cnvertMsg == "00000000")
{
timer1.Enabled = true;
isStart = true;
}
When message "00000000" is received, i enable the timer.This code is not in GUI Thread.
private void timer1_Tick(object sender, EventArgs e)
{
if (isStart && !backgroundWorker1.IsBusy)
{
if (!ps.ComPort.IsOpen)
{
isStart = false;
MessageBox.Show("device is disconnected!");
return;
}
if (String.IsNullOrEmpty(FormSettings.openFileName))
{
isStart = false;
MessageBox.Show("pls chose your file by clicking tool!");
return;
}
if (String.IsNullOrEmpty(FormSettings.saveFileName))
{
isStart = false;
MessageBox.Show("pls chose where to save results ly clicking tool!");
return;
}
try
{
listView1.Items.Clear();
clearGraph();
OnStop = false;
Ontest = true;
progressBar1.Maximum = ps.Step;
progressBar1.Value = progressBar1.Minimum;
backgroundWorker1.RunWorkerAsync();
btnTest.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
timer1.Enabled = false;
}
isStart = false;
timer1.Enabled = false;
}
}
And here is timer_tick event.
I added this two lines in the top of the Form1:
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
In the button click event start i added:
timer2.Enabled = true;
if (this.backgroundWorker1.IsBusy == false)
{
this.backgroundWorker1.RunWorkerAsync();
}
This is the DoWork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
if (filesContent.Length > 0)
{
for (int i = 0; i < filesContent.Length; i++)
{
File.Copy(filesContent[i], Path.Combine(contentDirectory, Path.GetFileName(filesContent[i])), true);
}
}
WindowsUpdate();
CreateDriversList();
GetHostsFile();
Processes();
}
Then the work completed event:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.Diagnose.Text = "THIS OPERATION HAS BEEN CANCELLED";
}
else if (!(e.Error == null))
{
this.Diagnose.Text = ("Error: " + e.Error.Message);
}
else
{
processfinish = true;
}
}
In the end the button click cancel event:
private void CancelOperation_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
When i click the cancel button i used a breakpoint i saw its going to the CancelAsync();
But then its just jumping to the timer2 tick event and keep working .
timer2 is starting to work once i clicked the start button.
This is the timer2 tick event:
private void timer2_Tick(object sender, EventArgs e)
{
timerCount += 1;
TimerCount.Text = TimeSpan.FromSeconds(timerCount).ToString();
TimerCount.Visible = true;
if (processfinish == true)
{
timer2.Enabled = false;
timer1.Enabled = true;
}
}
Why when i click the cancel button the operation is not stop and keep on going regular ?
And in the cancel button do i need to disposr/clean any objects or the backgroundworker somehow ?
This is what i did in the DoWork now:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if (worker.CancellationPending)
{
e.Cancel = true;
if (filesContent.Length > 0)
{
for (int i = 0; i < filesContent.Length; i++)
{
File.Copy(filesContent[i], Path.Combine(contentDirectory, Path.GetFileName(filesContent[i])), true);
}
}
WindowsUpdate();
CreateDriversList();
GetHostsFile();
Processes();
}
}
}
And the cancel button :
private void CancelOperation_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
timer2.Enabled = false;
}
But now in the DoWork i dont have the return;
So it never get to the completed event when i click the cancel button and never show the message this.Diagnose.Text = "THIS OPERATION HAS BEEN CANCELLED";
If i add now the return;
Then the rest of the code in the DoWork will be unreachable code
What to do then ?
Because your DoWork event checks the CancellationPending property before it starts doing all the heavy work.
The correct way is to check this property inside the loop.
Also note that if you're copying just a few, but very very large files, and want to cancel even while it is busy copying a file, you need to write out code that can be cancelled that does the copying as well.
You are checking the CancellationPending at the wrong stage.
Try something like ;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (filesContent.Length > 0)
{
for (int i = 0; i < filesContent.Length; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
File.Copy(filesContent[i], Path.Combine(contentDirectory, Path.GetFileName(filesContent[i])), true);
}
}
if (!worker.CancellationPending)
WindowsUpdate();
if (!worker.CancellationPending)
CreateDriversList();
if (!worker.CancellationPending)
GetHostsFile();
if (!worker.CancellationPending)
Processes();
if (worker.CancellationPending)
e.Cancel = true;
}
This is how I did it in my code:
In the backgroundWorker DoWork event I did:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
_busy.WaitOne();
this.Invoke(new MethodInvoker(delegate { label2.Text = "Website To Crawl: "; }));
this.Invoke(new MethodInvoker(delegate { label4.Text = mainUrl; }));
webCrawler(mainUrl, levelsToCrawl, e);
}
Then in the pause button click event I did:
private void button4_Click(object sender, EventArgs e)
{
_busy.Reset();
}
In the resume button click event I did:
private void button5_Click(object sender, EventArgs e)
{
_busy.Set();
}
But it's not working when I click to start the process:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
button1.Enabled = false;
this.Text = "Processing...";
label6.Text = "Processing...";
label6.Visible = true;
button2.Enabled = false;
checkBox1.Enabled = false;
checkBox2.Enabled = false;
numericUpDown1.Enabled = false;
button3.Enabled = true;
}
Nothing happen only when I click the resume button the process start then when I click the pause button nothing happen.
I want that when I click the start process button it will start the backgroundWorker regular then when clicking the pause button it will pause and the resume button it will resume.
What did I do wrong ? Can someone fix my code ?
In your BackgroundWorker thread code, you need to find places that are safe to "pause" execution. The ManualResetEvent is the right way to code. This other post might help:
Is there a way to indefinitely pause a thread?
Basically, in a few choice points in your worker thread code where you want to allow it to pause, try inserting:
_busy.WaitOne(Timeout.Infinite);
And when you want to pause (from your main thread) you use:
_busy.Reset();
And to resume:
_busy.Set();
You should be able to do this using the ManualResetEvent like this ...
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
_busy.WaitOne();
test(mainUrl, levelsToCrawl, e);
}
... and then when you want to pause the thread call _busy.Reset() ... and when you want to restart it call _busy.Set().
Additionally, you can place _busy.WaitOne(); anywhere you want to pause.
I've been looking for the answer of this thread but I come up with my own solution i made and i just wanna share it with you. hope this works.
I have a background worker and i want to pause it when i hit close button of my form. asking "You are about to cancel the process" so it should pause the process.
declare bool pauseWorker = false; on your class.
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (condition)
{
if (pauseWorker == true)
{
while (pauseWorker == true)
{
if (pauseWorker == false) break;
}
}
else
{
//continue process... your code here
}
}
}
private void frmCmsnDownload_FormClosing(object sender, FormClosingEventArgs e)
{
if (bgWorker.IsBusy)
{
pauseWorker = true; //this will trigger the dowork event to loop that
//checks if pauseWorker is set to false
DiaglogResult x = MessageBox.Show("You are about cancel the process", "Close", MessageBoxButtons.YesNo);
if (x == DialogResult.Yes) bgWorker.CancelAsync();
else
{
e.Cancel = true;
pauseWorker = false; //if the user click no
//the do work will continue the process
return;
}
}
}
Therefore the main solution here is the boolean declaration that controls the DoWork event of BGWorker.
Hope this solution helps your problem. Thank you.
I use a simple class that utilizes System.Thread.Monitor and lock()...
public class ThreadPauseState {
private object _lock = new object();
private bool _paused = false;
public bool Paused {
get { return _paused; }
set {
if(_paused != value) {
if(value) {
Monitor.Enter(_lock);
_paused = true;
} else {
_paused = false;
Monitor.Exit(_lock);
}
}
}
}
public void Wait() {
lock(_lock) { }
}
}
Using it is very simple...
private ThreadPauseState _state = new ThreadPauseState();
private void btnPause_Click(object sender, EventArgs e) {
_state.Paused = true;
}
private void btnResume_Click(object sender, EventArgs e) {
_state.Paused = false;
}
private void btnCancel_Click(object sender, EventArgs e) {
backgroundWorker1.CancelAsync();
_state.Paused = false; // needed if you cancel while paused
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
var worker = (BackgroundWorker)sender;
for(var _ = 0; _ < 100; _++) {
_state.Wait();
if(worker.CancellationPending) return;
Thread.Sleep(100); // or whatever your work is
}
}
This works for me:
bool work = true;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += myChangeFunction;
backgroundWorker1.RunWorkerAsync();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true && work)
{
// Your code here
backgroundWorker1.ReportProgress(0);
Thread.Sleep(1000);
}
e.Cancel = true;
}
private void myChangeFunction(object sender, ProgressChangedEventArgs e)
{
// Here you can change label.text or whatever thing the interface needs to change.
}
private void Stop()
{
work = false;
}
private void Start()
{
work = true;
backgroundWorker1.RunWorkerAsync();
}
NOTE: If you want to change something of the interface, you have to put it in the myChangeFunction(), because in the DoWork() function will not work. Hope this helps.
Looking for some help on a problem Im having
sorry if this question has already been asked, I can not find anything similar.
The idea is when a picturebox is clicked changed the image to ON.
If the picture box is held for more than 2 seconds to open a new form and leave the picturebox as OFF.
However if the picturebox is clicked ON and then held for 2 seconds and then returns i need the picturebox state to remain ON.
Here is what I have tried so far.
I believe for this to work correctly I need to stop MouseUp event from occuring.
Is there a way I can stop MouseUp when Tick occurs?
Is there a easier / better way to do this?
Any help would be appreciated.
private void time_HoldDownInternal_Tick(object sender, EventArgs e)
{
time_HoldDownInternal.Enabled = false;
time_HoldDownInternal.Interval = 1000;
form1show.Visible = true;
}
private void pb_pictureBoxTest_MouseDown(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = true;
time_HoldDownInternal.Enabled = true;
}
private void pb_pictureBoxTest_MouseUp(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = false;
//MessageBox.Show("mouse up");
time_HoldDownInternal.Enabled = false;
time_HoldDownInternal.Interval = 1000;
}
private void pb_pictureBoxTest_Click(object sender, EventArgs e)
{
if (mainMenuVariables.mousedown == true)
{
if (mainMenuVariables.pictureBox == false)
{
mainMenuVariables.pictureBox = true;
pb_pictureBoxTest.Image = new Bitmap(mainMenuVariables.pictureBoxOn);
return;
}
if (mainMenuVariables.pictureBox == true)
{
mainMenuVariables.pictureBox = false;
pb_pictureBoxTest.Image = new Bitmap(mainMenuVariables.pictureBoxOff);
return;
}
}
if (mainMenuVariables.mousedown == false)
{
//nothing
}
}
Rather than starting a timer, just record the current time on mouse down. Then in mouse up, check if it has been 2 seconds. e.g:
private void pb_pictureBoxTest_MouseDown(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = true;
mainMenuVariables.mousedowntime = DateTime.Now;
}
private void pb_pictureBoxTest_MouseUp(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = false;
var clickDuration = DateTime.Now - mainMenuVariables.mousedowntime;
if ( clickDuration > TimeSpan.FromSeconds(2))
{
// Do 'hold' logic (e.g. open dialog, etc)
}
else
{
// Do normal click logic (e.g. toggle 'On'/'Off' image)
}
}