How to use Key Event in Timer? - c#

I have the following code, which on key press, starts moving the two labels from top of the form to the bottom, and after reaching the bottom of the form, it stops. I have done it using the timer. Here is the code
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
label1.Text = "Key Pressed: " + e.KeyChar;
//animate(sender, e);
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
Random random = new Random();
int X = random.Next(0, 1230);
int y = X;
label2.Location = new Point(X, 5);
label3.Location = new Point(X + 20, 5 + 20);
for (int i = 5; i <= 470; i++)
{
label2.Location = new Point(y, i);
label3.Location = new Point(y + 20, i + 20);
Thread.Sleep(1);
}
timer1.Stop();
}
Now during the animation (from the top of the form to the bottom), when I press the key, the animation restarts after reaching the bottom i.e. it completes the tick event and then and only then starts over or stop.
Now what I want is that whenever, during this movement of the labels from the top to bottom i.e. during the tick, if I press any key (or any specific key), the timer should stop.
In short, during the Timer1_Tick method, I want it to stop immediately on a key press.
I tried but couldn't get it to work. I hope that you folks here would help me sort this issue out and hope that you reply on your earliest. Thank you for your time!

The problem here is that you are not really using the Timer in the way that it's intended to be used. Ideally you would have an event that makes a change every time the tick event fires for a Timer.
Here you listen to the event and do several rounds of processing without ever returning from the handler at which point you stop the timer. This means the code will only ever process the tick event once instead of N times.
To fix this try breaking up the handler to do incremental work once per tick and only stop once the drawing is complete. This will also allow you to handle key events in between the tick events and stop the timer. The best place to break up the work is at the Thread.Sleep call (which itself should not appear in the handler)

Try it is so simple
Public Boolean tick = false;
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
tick = !tick;
label1.Text = "Key Pressed: " + e.KeyChar;
//animate(sender, e);
if(tick)
timer1.Start();
else
timer1.Stop();
}

First of all i recommend you to use keyDown and keyUp events instead of key press. To solve your problem: simple set a bool = true on keyDown and and the bool = false on keyUp. Now you can check the bool within you tick method and do whatever you want if you detect key is being pressed.

Related

Long Press Detector with c# in xamarin.forms

I am making a simple calculator app where the DEL button removes the last digit in the viewport, but if held down for one second it deletes everything in the viewport. Right now If I press the button once, it deletes the last digit whether I hold it down or not. If I press it down again (held down or just a regular tap) it clears everything in the viewport and I cannot type anything else in.
Firstly I create the timer like so:
public System.Timers.Timer timer = new System.Timers.Timer(1);
and then I have a function for when the 'DEL' button is pressed:
private void DeletePressed(object sender, EventArgs args)
{
timer.Stop();
timer.Start();
timer.Elapsed += AllClear;
}
a function to stop the timer and delete the last character from the viewport when the button is released:
private void DeleteReleased(object sender, EventArgs args)
{
timer.Stop();
if (CalculatorString.Length > 0)
{
CalculatorString = CalculatorString.Remove(CalculatorString.Length - 1);
}
viewport.Text = CalculatorString;
}
and finally the procedure that is called when the timer finishes:
private void AllClear(Object Source, System.Timers.ElapsedEventArgs e)
{
timer.Stop();
CalculatorString = "";
viewport.Text = CalculatorString;
}
however none of what I expected tohas happened. I appreciate any help in advance :)
There is no direct way to listen long press in Xamarin.Forms(PCL). You have to write separate custom renderers for each platform to Listen long press and communicate it to the PCL.
You can refer this link for code example for doing the same.

How to disable and after enable the click receiving...?

I wanna reset the MouseEventArgs to always run only once.
If somebody click the button more than once (10 times) then the program run 10x and so on.
My code doesn't work well, because if someone click on the button1 2x or more times it will be runned.
I wanna reset the MouseEventArgs or do other solution.
Windows Form Application (XP, 32bit)
private void button1_MouseClick(object sender, MouseEventArgs e)
{
button1.Enabled = false;
button1.MouseClick -= button1_MouseClick;
mc++;
if (true)
{
button1.Enabled = false;
//button1.Location = new Point(40, 40);
//Point location = button1.Location;
//location.X = 0; location.Y = 0;
System.Threading.Thread.Sleep(2000);
if (mc == 1)
{
//button1.Location = new Point(67, 191);
//location.X = 67; location.Y = 191;
mc = 0;
button1.Enabled = true;
button1.MouseClick += button1_MouseClick;
textBox1.AppendText("Click " + e.Clicks + ", Clicks: " + mc + "\n");
}
}
}
You are trying to execute some long running job on the main thread.
It might look like you disabled the button and following clicks should be ignored but they are actually placed in a queue. If you take a look at the events queue every click is done when the button is enabled:
Click
Disable button
Wait 2 seconds
Enable button
Click
...
Try the following code:
private void button1_MouseClick(object sender, MouseEventArgs e)
{
//disable button on main thread
button1.Enabled = false;
Thread worker = new Thread(() =>
{
//do time consuming job
System.Threading.Thread.Sleep(2000);
//enable button (from the main thread)
this.Invoke((MethodInvoker)delegate
{
textBox1.AppendText("Click " + e.Clicks + "\n");
button1.Enabled = true;
});
});
worker.Name = "Button 1 worker";
worker.Start();
}
Now the time consuming job is done on separate thread and the UI events will work as expected:
Click
Disable button
Do job on another thread ------------> Wait 2 seconds
Click - ignored (button is disabled) |
Click - ignored (button is disabled) |
Click - ignored (button is disabled) |
Click - ignored (button is disabled) |
Enable button
Click
Disable button ...
Instead of writing logic inside the event try to make a custom control that extend System.Windows.Forms.Button.
But as far as I can understand your code make you click event handler always be linked with the function, if mc value start with 0.
Hope it helps
When you disabled your button is may not receive any mouse-events further so you do not have to change any event-handlers. Write your code that should be executed once within your handler and disable the button. Thus the code cannot be executed any longer as long as the button is disabled.

How to catch event Mouse Hold on a control?

I want to catch the event that user clicks and holds mouse on a control in C#.
I have read on MSDN and I only see events Mouse Down, Mouse Up, ... but don't have Move Hold event.
You need to use mentinoed events with some timer between them.
Example:
MouseDown
Start Timer
MouseUp
Disable Timer
In case if user holds more then timer time - invoke your event handler, when mouseUp happend faster then timer elapsed - disable runned timer.
First, you should use stop watch to detect time you want.
using System.Diagnostics;
Second, define a global instance of stopwatch class.
Stopwatch s = new Stopwatch();
This is the first event you should use:
private void controlName_MouseDown(object sender, MouseEventArgs e)
{
s.Start();
}
This is the second event you should use:
private void controlName_MouseUp(object sender, MouseEventArgs e)
{
s.Stop();
//determine time you want . but take attention it's in millisecond
if (s.ElapsedMilliseconds <= 700 && s.ElapsedMilliseconds >= 200)
{
//you code here.
}
s.Reset();
}

c# Shutdown a system after holding yes for 5 seconds

I was wondering if anyone knows how to use a dialog box to create a hold down button event. Here is the scenerio:
a user would like to shutdown their system, but because it is critical that they confirm, that user must hold the button for 5 seconds before the action can be done.
I am trying to do it in a yes no scenario ie.
To confirm shutdown please hold "Yes" for 5 seconds.
Anyone done this before able to offer a little help/insight?
Try using a button's Mouse_Down & Mouse_Up event, and a timer (this assumes you're using WinForms).
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (this.timer1.Enabled == false)
{
this.timer1.Interval = 5000;
this.timer1.Enabled = true;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
this.timer1.Enabled = false;
MessageBox.Show("Shutdown!");
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
timer1.Enabled = false;
}
You could capture the button press on 'mousedown', and start a 5-second timer. Once the timer completes, shutdown is initiated. If a 'mouseup' event happens, it could stop and reset the timer.
Sure, handle BOTH the mousedown event and the mouseup event. Start a timer on the mousedown and see how long it has run on the mouseup. Done!
You could do this any number of ways. The first that comes to my mind would be to spin off a thread that waits 5 seconds and is simply aborted if the user's mouse comes back up.
Thread shutdown;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
shutdown = new Thread(()=>ShutDown());
shutdown.Start();
}
private void ShutDown()
{
Thread.Sleep(5000);
Console.Write("5 seconds has elapsed");
// Do something.
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
if (shutdown != null)
{
shutdown.Abort();
shutdown = null;
}
}
Low overhead and you're not adding additional supporting controls for something this simple.
Why bother when you can just use getAsyncKeyState()? Tell them to hold down 'y' for 5 seconds. You can find a reference here: http://www.pinvoke.net/default.aspx/user32.getasynckeystate
Or you can do it your way and start a timer on MouseDown, then on MouseUp, end the timer and then see if it's more or less than 5 seconds. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mousedown%28VS.71%29.aspx
You can use the Form.MouseDown events do detect that the user has pressed the mouse button. In the event handler, check to see if cursor is over the button or not (the event is passed in the coordinates of the cursor). You can then enable a timer which will tick in 5 seconds, and perform the shutdown when the timer ticks.
When the user first clicks YES, start a timer that repeatedly checks if the mouse location is inside of the button. After 5 seconds has elapsed, proceed with the shutdown. If the user moves the mouse out of the button, stop the timer.
private DateTime mouseDownTime;
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
mouseDownTime = DateTime.Now;
}
private void Button_MouseUp(object sender, MouseButtonEventArgs e)
{
if (mouseDownTime.AddSeconds(5) < DateTime.Now)
MessageBox.Show("You held it for 5 seconds!");
}
You can set up a timer on the MouseDown event, and if the mouse capture changes (check the MouseCaptureChanged event) to false before the timer event fires, cancel the timer.

How can I stop my while loop?

I would like to use the following code in C# but I just can't seem to get out of it. I would like to terminate the application if the user presses a key or moves the rodent (aka mouse). Here is my code (no laughing!).
private void frmDots_KeyDown(object sender, KeyEventArgs e)
{
bgNotClicked = false;
Close();
}
private void frmDots_Click(object sender, EventArgs e)
{
bgNotClicked = false;
Close();
}
while (bgNotClicked)
{
// Clear the first element in our XY position. This is the reverse of the way I normally create the dots application
System.Drawing.Rectangle clearDots = new System.Drawing.Rectangle(Dots.PositionX[iCounter], Dots.PositionY[iCounter], 8, 8);
// Create the black color and brush to clear dots
Color clearDotsColor = Color.Black;
SolidBrush clearDotsBrush = new SolidBrush(clearDotsColor);
// Finally clear the dot
e.Graphics.FillEllipse(clearDotsBrush, clearDots);
GetRandomPosition(iCounter);
// Fill the elements to display colors on the displays canvas
System.Drawing.Rectangle colorDots = new System.Drawing.Rectangle(Dots.PositionX[iCounter], Dots.PositionY[iCounter], 8, 8);
// Create the color and brush to show dots
Color colorRandom = GetRandomColor();
SolidBrush colorBrush = new SolidBrush(colorRandom);
// Finally show the dot
e.Graphics.FillEllipse(colorBrush, colorDots);
Thread.Sleep(5);
iCounter++;
if (iCounter == 399)
{
iCounter = 0;
}
}
}
Your "busy waiting" strategy is poor design. Instead, you should use event handlers that are fired:
On keypress.
When the mouse is moved.
In either case, you can respond by terminating the application.
Edit:
After seeing your edit, this is definitely your problem. The issue is that your while loop blocks the main UI thread, so it never handles the Windows Messages which trigger your key press/mouse/etc handlers.
You have a couple of options - you can either move some of this onto a separate thread, do what I suggested below, or add a call to Application.DoEvents in your while loop. This would allow your event handlers to run, which would in turn set bgNotClicked = false;. Right now, that's never occurring because your UI is blocked entirely.
Original Post:
If you're doing this loop in your UI thread, you're going to need to rethink the design a bit.
Setting bgNotClicked = false; somewhere in an event handler will work, but only if your event handler is able to run. If you're doing the above code in the UI thread, it will block your UI thread indefinitely, preventing the event handler from firing.
I would recommend reworking this to be based off a timer (so it runs repeatedly on regular intervals), instead of locked into a while loop. This would allow your other UI events to fire between runs, and instead of setting bgNotClicked = false;, your event handler could just set the timer to be not enabled.
Your bgNotClicked variable needs to be set to false by your event handler for key-press.
If the rodent is moved by your mouse, you would need a similar mouse event handler.
The break keyword will terminate a loop. In this case, when you hit the case where you want to stop the loop, you would just use break;.
If you're looping like that you need to give the application a moment to process the events that you're hoping will cause the interruption. This is the job of the DoEvents method.
private bool WeAreDone = false;
private void DoingIt()
{
while (true)
{
Application.DoEvents();
if (WeAreDone)
{
break;
}
}
}
private void InterruptButton_Click(object sender, EventArgs e)
{
WeAreDone = true;
}
I think using a Timer fits the Windows event-driven model better than the busy wait while loop. You might try something like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int iCounter = 0;
private void Draw()
{
// ....
}
private void timer1_Tick(object sender, EventArgs e)
{
Draw();
iCounter++;
if(iCounter == 399)
{
iCounter = 0;
}
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 5;
timer1.Enabled = true;
}
private void Form1_Click(object sender, EventArgs e)
{
timer1.Enabled = false;
Close();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
timer1.Enabled = false;
Close();
}
}
This does not seems to be the correct way. .Net Framework has provided you with the events to handle the KeyPress and MouseMove/Click actions. Why are you not using them?
Try moving the loop into a BackgroundWorker's DoWork event handler. Then your GUI will still be responsive and instead of that nasty variable, you can just call the CancelAsync method to stop the loop.
You can exit the loop using the break statement.
EDIT: OK, I take back the flag thing!
Use Environment.Exit(2); (or Environment.Exit(1) it really doesn't make a difference) to exit out of the application.
Exit While
...................

Categories

Resources