Set xTime on Condition Inside KeyEvent - c#

is there a way i can set a condition that after pressing key and if 5seconds already passed then a certain method will be executed .
e.g i have keyup event in gridview:
private void Grid_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
}
else
{
if (atimehasalreadypassed == 5seconds)
{
//execute
}
}
}
problem with this was count might start after passing keyDown so it would be only 1sec.
so i need some count outside U.I thread / within background thread ...
Note: i dont need delay, i just need to know if 5seconds already passed after keyEvent ...

This might be what you need:
private void Grid_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
}
else
{
if (SecondsPassed(5))
{
//execute
}
}
}
private DateTime _lastCallTime = new DateTime();
private bool SecondsPassed(double seconds)
{
// calculate time difference
var timeSpan = new TimeSpan(DateTime.Now.Ticks - _lastCallTime.Ticks);
// reset timing
_lastCallTime = DateTime.Now;
if (timeSpan.TotalSeconds > seconds)
{
return true;
}
return false;
}
Note that you might want to initialize "_lastCallTime" manually, depending on your usage.

Related

Why my timer wont work? C# i want to start Thread on pressing a key and to stops automatically

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.

How to get text of NumericUpDown before valuechanged event?

I want to make it work this way: when I write to NumericUpDown 1k the value should be 1000, when I write 4M the value should be 4000000. How can I make it?
I tried this:
private void NumericUpDown1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyValue == (char)Keys.K)
{
NumericUpDown1.Value = NumericUpDown1.Value * 1000;
}
}
But it works with the original value that I wrote.
I want to make it work as a macroses. For example, If I want to get NUD1.Value 1000, I write 1 and then, when I press K the NUD1.Value becomes 1000.
Let's assume we have a NumericUpDown named numericUpDown1. Whenever the user presses k, we want to multiply the current value of the NUP by 1,000, and if the user presses m, the current value should be multiplied by 1,000,000. We also don't want the original value to trigger the ValueChanged event. So, we need to have a bool variable to indicate that the value is being updated.
Here's a complete example:
private bool updatingValue;
private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData != Keys.K && e.KeyData != Keys.M) return;
int multiplier = (e.KeyData == Keys.K ? 1000 : 1000000);
decimal newValue = 0;
bool overflow = false;
try
{
updatingValue = true;
newValue = numericUpDown1.Value * multiplier;
}
catch (OverflowException)
{
overflow = true;
}
updatingValue = false;
if (overflow || newValue > numericUpDown1.Maximum)
{
// The new value is greater than the NUP maximum or decimal.MaxValue.
// So, we need to abort.
// TODO: you might want to warn the user (or just rely on the beep sound).
return;
}
numericUpDown1.Value = newValue;
numericUpDown1.Select(numericUpDown1.Value.ToString().Length, 0);
e.SuppressKeyPress = true;
}
And the ValueChanged event handler should be something like this:
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
if (updatingValue) return;
// Simulating some work being done with the value.
Console.WriteLine(numericUpDown1.Value);
}

While Loop Function after a button is pressed and stop looping when another button is pressed C#

In my Windorm Form application, I have two buttons which a loop function will begin to do the work when button1 is pressed and stop executing after button2 is pressed. How could i do this to prevent my GUI from non-responsive.
How could i insert command while(button2.clicked != true)
My code for button 1:
private async void EmoStart_Click_1(object sender, EventArgs e)
{
//var repeat = "true";
string imageFilePath = "C:\\Users\\Administrator\\source\\repos\\FaceDetection\\FaceDetection\\test3.jpg";
while (VoiceStart_Click_2 != "true")
{
var image = pictureBox1.Image;
image = resizeImage(image, new Size(1209, 770));
image.Save(imageFilePath);
if (File.Exists(imageFilePath))
{
var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);
if (Emo[0].FaceAttributes.Emotion.Anger >= 0.5)
{
EmoBox.Text = "Anger, Bad Driving Condition, Soft Music will be played";
}
else if (Emo[0].FaceAttributes.Emotion.Contempt >= 0.5)
{
EmoBox.Text = "Contempt, Bad Driving Condition, Soft Music will be played";
}
else if (Emo[0].FaceAttributes.Emotion.Disgust >= 0.5)
{
EmoBox.Text = "Disgust, Bad Driving Condition, Soft Music will be played";
}
else if (Emo[0].FaceAttributes.Emotion.Fear >= 0.5)
{
EmoBox.Text = "Fear, Bad Driving Condition, Soft Music will be played";
}
else if (Emo[0].FaceAttributes.Emotion.Happiness >= 0.5)
{
EmoBox.Text = "Happiness, Good Driving Condition";
}
else if (Emo[0].FaceAttributes.Emotion.Neutral >= 0.5)
{
EmoBox.Text = "Neutral, Good Driving Condition";
}
else if (Emo[0].FaceAttributes.Emotion.Sadness >= 0.5)
{
EmoBox.Text = "Sadness, Bad Driving Condition, Rock Music will be played";
}
else if (Emo[0].FaceAttributes.Emotion.Surprise >= 0.5)
{
EmoBox.Text = "Happiness, Bad Driving Condition, Soft Music will be played";
}
else
{
EmoBox.Text = "Stable Condition, Good Driving Condition";
}
}
}
While for my button2 code:
private async void VoiceStart_Click_2(object sender, EventArgs e)
{
string command = await Voice.RecognizeSpeechAsync();
VoiceBox.Text = command;
}
Thank you!
You have to run your loop in a separate thread. For example, you can run it asynchroniously. Something like this:
// start the loop
private async void button1_Click(object sender, EventArgs e)
{
LoopStopped = false;
await StartLoopAsync();
}
// put yor while loop here
private Task StartLoopAsync()
{
return Task.Run(() =>
{
while (LoopStopped == false)
{
var date = DateTime.Now;
System.Diagnostics.Debug.WriteLine(date);
}
System.Diagnostics.Debug.WriteLine("Thread stopped.");
});
}
// stop the loop
private void button2_Click(object sender, EventArgs e)
{
LoopStopped = true;
}
Where LoopStopped is global boolean variable.
All the operations you put into the EmoStart_Click_1 is running synchronously, except:
FaceEmotion.MakeAnalysisRequest(imageFilePath)
thus the interface (UI) is frozen.
It is not enough to change the signature of the method to async as you did. You must tell the compiler, which other parts should be awaited. You want your whole while function async!
private async void EmoStart_Click_1(object sender, EventArgs e)
{
EmoStart.Enabled = false; //I assume EmoStart is the name of your button
await Task.Factory.StartNew(Loop);
EmoStart.Enabled = true;
}
private void Loop() //since this method doesn't have async in its signature "var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);" won't compile, so you should change to the synchronous equivalent "var Emo = FaceEmotion.MakeAnalysisRequest(imageFilePath).Result;" --> note that it won't block due to "Task.Factory.StartNew".
{
string imageFilePath = "C:\\Users\\Administrator\\source\\repos\\FaceDetection\\FaceDetection\\test3.jpg";
while (...)
{
// do your stuff
}
Then you can decide how you want to cancel the while loop.
Option 1.: you could use a global, bool variable:
private bool emotionsShouldBeProcessed;
and you set it true in EmoStart_Click_1 and false like this:
private async void VoiceStart_Click_2(object sender, EventArgs e)
{
VoiceStart.Enabled = false;
emotionsShouldBeProcessed = false;
// start and await voice stuff
VoiceStart.Enabled = true;
}
Option 2.: you could use a CancellationToken to track if cancel is necessary.
CancellationTokenSource cSource;
private async void EmoStart_Click_1(object sender, EventArgs e)
{
EmoStart.Enabled = false;
cSource = new CancellationTokenSource();
await Task.Factory.StartNew(() => Loop(cSource.Token));
EmoStart.Enabled = true;
}
private void Loop(CancellationToken cToken)
{
string imageFilePath = "C:\\Users\\Administrator\\source\\repos\\FaceDetection\\FaceDetection\\test3.jpg";
while (true)
{
if (cToken.IsCancellationRequested)
break;
// otherwise do your stuff
}
// some clean up here if necessary
}
private async void VoiceStart_Click_2(object sender, EventArgs e)
{
VoiceStart.Enabled = false;
cSource.Cancel();
VoiceStart.Enabled = true;
}
So far so good! But your code will crash
It will crash whenever you want to set EmoBox.Text as this can happen only on the UI thread. To avoid this, you need to ask the UI thread to interrupt until Textbox/Label/etc operations are going on, like this:
this.Invoke((MethodInvoket)delegate
{
EmoBox.Text = "...";
});
Edit:
I would also check the Emo array whether it is empty since face- and emotion recognitions not always succeeds! Thus, Emo[0] can result in "Index was out of range" exception. Following code makes sure it isn't empty:
var Emo = ...;
if (Emo.Length > 0)
{
if (...)
// use Emo[0]
else if (...)
// use Emo[0] differently
}
Let me know if there is anything unclear.
You can create a bool variable and make the loop while your variable is true.
So set the variable to true, when button1 is clicked.
Then your while would look like this:
while(myBoolVariable)
And when button2 is clicked you can change the value to false and the while will stop.
You can use a global variable(bool is a good choice)
when VoiceStart_Click_2 change the variable
and do check the variable when EmoStart_Click_1 is clicked
if (variable==true)
{
var Emo = await FaceEmotion.MakeAnalysisRequest(imageFilePath);
if (Emo[0].FaceAttributes.Emotion.Anger >= 0.5)
{
EmoBox.Text = "Anger, Bad Driving Condition, Soft Music will be played";
}
...
}

C# If more keys are pressed at once how to not stop functions of others?

I know the title was little unclear but i will explain.
My Example:
when i press 'D' my object will move to right,
same for 'A' just move to left,
but when i press 'Space' while holding 'A'/'D',the object will just o the function of the 'Space'.
if (e.KeyCode == Keys.A)
{
ply.Left -= 3;
}
if (e.KeyCode == Keys.D)
{
ply.Left += 3;
}
if (e.KeyCode == Keys.Space) {
ply.Top -= 100;
}
You can track the state of multiple keys through the use of both KeyUp and KeyDown by use of a HashSet<Keys>:
private HashSet<Keys> _keys = new HashSet<Keys>();
public void Control_KeyDown(object sender, KeyEventArgs e)
{
_keys.Add(e.KeyCode);
}
public void Control_KeyUp(object sender, KeyEventArgs e)
{
_keys.Remove(e.KeyCode);
}
public bool IsKeyDown(Keys keyCode)
{
return _keys.Contains(keyCode);
}
Now, whenever you want to check to see if a key is down, just do:
if(IsKeyDown(Keys.A))
{
ply.Left -= 3;
}
Keep in mind that if you just check key states in one of the key events, you will probably have issues with not detecting repeats properly. If you really want to handle this properly, you should use a Timer with a fairly small Interval that periodically polls with IsKeyDown and handles all your input.
With a Timer named timer1 that has an interval of 100, you can handle all your input like this, and have fairly responsive input to the full range of keys supported by your hardware.
private void timer1_Tick(object sender, EventArgs e)
{
if (IsKeyDown(Keys.A))
{
ply.Left -= 3;
}
if (IsKeyDown(Keys.S))
{
ply.Top += 3;
}
if (IsKeyDown(Keys.D))
{
ply.Left += 3;
}
if (IsKeyDown(Keys.W))
{
ply.Top -= 3;
}
}
As Bradley said, you could save all key events to a keystate cache.
This could look something like this pseudo code:
Event KeyDown(e) -> keystate[e.KeyCode] = true
Event KeyUp(e) -> keystate[e.KeyCode] = false
That way, you should always know every state.

Timer, click, mousedown, mouseup events not working together

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)
}
}

Categories