Timer intervals, Making 1 timer stop another timer - - c#

Hey guys im trying to get a simple button masher up, What i want timer1 to do is mash keys in richtextbox1 for 30 seconds over and over, after 30 seconds Activate timer2, which will disable timer 1 and press keys in richtextbox 2 once, then wait 10 seconds and activate timer 1 again.
Im extremley new to c# but ive tried using timer 3 to stop timer 2 and start timer 1 again and it just messes it self up. The code ive tried is below. Any help apreciated...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
SendKeys.Send(richTextBox1.Text);
SendKeys.Send("{ENTER}");
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
timer2.Enabled = true;
}
private void timer2_Tick(object sender, EventArgs e)
{
SendKeys.Send(richTextBox2.Text);
SendKeys.Send("{ENTER}");
timer1.Enabled = false;
}
private void timer3_Tick(object sender, EventArgs e)
{
timer1.Enabled = true;
timer2.Enabled = false;
}
private void richTextBox2_TextChanged(object sender, EventArgs e)
{
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
}
}

I suggest to use just one timer, increment a state counter every second, and perform an action base on the current state.
public Form1()
{
this.InitializeComponent();
// Just to illustrate - can be done in the designer.
this.timer.Interval = 1000; // One second.
this.timer.Enable = true;
}
private Int32 state = 0;
private void timer_Tick(Object sender, EventArgs e)
{
if ((0 <= this.state) && (this.state < 30)) // Hit text box 1 30 times.
{
SendKeys.Send(this.richTextBox1.Text);
SendKeys.Send("{ENTER}");
}
else if (this.state == 30) // Hit text box 2 once.
{
SendKeys.Send(this.richTextBox2.Text);
SendKeys.Send("{ENTER}");
}
else if ((31 <= this.state) && (this.state < 40)) // Do nothing 9 times.
{
// Do nothing.
}
else
{
throw new InvalidOperationException(); // Unexpected state.
}
// Update state.
this.state = (this.state + 1) % 40;
}
The variant with two numeric up down controls.
public Form1()
{
this.InitializeComponent();
// Just to illustrate - can be done in the designer.
this.timer.Interval = 1000; // One second.
this.timer.Enable = true;
}
private Int32 state = 0;
private void timer_Tick(Object sender, EventArgs e)
{
Decimal n1 = this.numericUpDown1.Value;
Decimal n2 = this.numericUpDown2.Value;
if ((0 <= this.state) && (this.state < n1))
{
SendKeys.Send(this.richTextBox1.Text);
SendKeys.Send("{ENTER}");
}
else if (this.state == n1)
{
SendKeys.Send(this.richTextBox2.Text);
SendKeys.Send("{ENTER}");
}
else if ((n1 <= this.state) && (this.state < n1 + n2))
{
// Do nothing.
}
else
{
// Reset state to resolve race conditions.
this.state = 0;
}
// Update state.
this.state = (this.state + 1) % (n1 + n2);
}

If timer3 is running continuously, won't it start timer1 and stop timer2 at unpredictable times, without warning?
IOW, what starts and stops timer3?
As JustLoren pointed out, there might be a cleaner way to do this. Perhaps a single timer event and some controlling logic and flags, rather than trying to juggle three timers.

Related

Progressbar does not move (WinForms, .Net and BackgroundWorker)

Introduction
I am trying to make a WinForms app using .Net.
I am using tutorial from here wich shows BackgroundWorker and ProgressBar integration.
I added ProgressBar and BackgroundWorker controls to the form.
The names are the same as in example. Additionaly, i set WorkerReportProgress property to True for BackgroundWorker. No errors are shown and project compiles sucessfully...
Problem
The problem is - progressbar does not move.
And yet, it moves when clicked manually... progressBar1.PerformStep();.
What am i missing?
Code
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Start the BackgroundWorker.
BackgroundWorker1.RunWorkerAsync();
}
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
// Wait 500 milliseconds.
Thread.Sleep(500);
// Report progress.
BackgroundWorker1.ReportProgress(i);
}
}
private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString();
}
private void button2_Click(object sender, EventArgs e)
{
progressBar1.PerformStep();
}
}
}
Update
Removed progressBar1.PerformStep(); from DoWork and ProgressChanged.
Still the problem persists (ProgressBar does not move).
Thank you for ideas so far, will look into it more on Monday.
After you made sure you attached the event handlers to ProgressChanged and DoWork:
Remove progressBar1.PerformStep() from DoWork event handler.
Then use just progressBar1.Value = e.ProgressPercentage; in ProgressChanged event handler.
I wrote a simple Multithreading with Progress bar code a few years back. Hope it helps you:
#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
if (!bgwPrim.IsBusy)
{
//Prepare ProgressBar and Textbox
int temp = (int)nudPrim.Value;
pgbPrim.Maximum = temp;
tbPrim.Text = "";
//Start processing
bgwPrim.RunWorkerAsync(temp);
}
}
private void btnPrimCancel_Click(object sender, EventArgs e)
{
if (bgwPrim.IsBusy)
{
bgwPrim.CancelAsync();
}
}
private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
int highestToCheck = (int)e.Argument;
//Get a reference to the BackgroundWorker running this code
//for Progress Updates and Cancelation checking
BackgroundWorker thisWorker = (BackgroundWorker)sender;
//Create the list that stores the results and is returned by DoWork
List<int> Primes = new List<int>();
//Check all uneven numbers between 1 and whatever the user choose as upper limit
for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
{
//Report progress
thisWorker.ReportProgress(PrimeCandidate);
bool isNoPrime = false;
//Check if the Cancelation was requested during the last loop
if (thisWorker.CancellationPending)
{
//Tell the Backgroundworker you are canceling and exit the for-loop
e.Cancel = true;
break;
}
//Determin if this is a Prime Number
for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
{
if (PrimeCandidate % j == 0)
isNoPrime = true;
}
if (!isNoPrime)
Primes.Add(PrimeCandidate);
}
//Tell the progress bar you are finished
thisWorker.ReportProgress(highestToCheck);
//Save Return Value
e.Result = Primes.ToArray();
}
private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgbPrim.Value = e.ProgressPercentage;
}
private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pgbPrim.Value = pgbPrim.Maximum;
this.Refresh();
if (!e.Cancelled && e.Error == null)
{
//Show the Result
int[] Primes = (int[])e.Result;
StringBuilder sbOutput = new StringBuilder();
foreach (int Prim in Primes)
{
sbOutput.Append(Prim.ToString() + Environment.NewLine);
}
tbPrim.Text = sbOutput.ToString();
}
else
{
tbPrim.Text = "Operation canceled by user or Exception";
}
}
#endregion
Normally when writing a UI Element from a Alterante Thread, you have to use Invoke. BackgroundWorker is nice and Invoking the "ReportProgress" and "RunWorkerCompleted" Events on the thread that created it (wich should be the GUI thread) so you do not have to deal with that part of Multithreading wonkyness yet.
It is also nice enough to catch any Exceptions that would normally escape DoWork and be swallowed, exposing them to you in the Completed Event Args. Swallowing Exceptions is a huge issue with Multithreading.
The core issue is, that your loop breaks due to a Exception. Calling progressBar1.PerformStep(); inside the DoWork Event has to throw a "CrossThreadException". The BackgroudnWorker finishes (due to an exception) instantly. The RunWorker completed event is triggered when i was just the initial value.

How to generate random integers in a text box in C#

How do I randomly generate integer values in a text box for every one second till I click on a button.
I came up with following code (Clicking on Button 1 should generate random integers for every 1 second in textBox1 till Button2 is clicked) and its not working (Output is empty text box).
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
bool buttonclicked = false;
System.Timers.Timer myTimer;
System.Random r = new System.Random();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
while (buttonclicked == false)
{
myTimer = new System.Timers.Timer();
myTimer.Elapsed += new ElapsedEventHandler(rnd);
myTimer.Interval = 1000;
myTimer.Start();
}
}
public void rnd(Object sender, EventArgs e)
{
textBox1.Text = r.Next(0, 1000).ToString();
}
private void button2_Click(object sender, EventArgs e)
{
buttonclicked = true;
myTimer.Stop();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
}
Your while(buttonclicked == false) will create an infinite loop once you click the button.You can just do
private void button1_Click_1(object sender, EventArgs e)
{
myTimer = new System.Timers.Timer();
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(rnd);
myTimer.Interval = 1000;
myTimer.Start();
}
private void button2_Click_1(object sender, EventArgs e)
{
myTimer.Stop();
}
and you need to make a safe thread call to the textbox by doing :
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
And to set the text just use SetText(r.Next(0 ,1000).ToString());
Looks like it is because you are using a while loop instead of an if block. Your condition should look like this:
if( buttonclicked == false)
{
....
}
I think you were right to a loop - but not the timer.
No need to declare the System.Random at the class level either - unless you're using it elsewhere.
Using a for loop.
private void button1_Click_1(object sender, EventArgs e)
{
var r = new System.Random();
for (var i = 0; i < 1000; i++)
{
textBox1.Text = r.Next(0, 1000).ToString();
}
}
Using a while loop.
private void button1_Click_1(object sender, EventArgs e)
{
var r = new System.Random();
var i = 0;
while (i < 1000)
{
textBox1.Text = r.Next(0, 1000).ToString();
i++;
}
}
If you really want to add a new number each second, you could use async and await (to stop UI blocking) and add a System.Threading.Thread.Sleep(1000);.
Or even Task based would be better than a Timer (in my opinion). It's good to understand how Tasks work.
A Timer is okay for this scenario - but in real applications they can get messy, especially with multiple timers.
Here is an example of how the above would work using Tasks.
private void button1_Click(object sender, EventArgs e)
{
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => AddRandomNumbers(uiScheduler));
}
private async Task AddRandomNumbers(TaskScheduler uiScheduler)
{
var r = new Random();
for (int i = 0; i < 1000; i++)
{
await Task.Factory.StartNew(
() => textBox1.Text = r.Next(0, 1000).ToString(),
CancellationToken.None,
TaskCreationOptions.None,
uiScheduler);
Thread.Sleep(1000);
}
}

Form timer doesn't start

So I just started learning C# and using forms. I have been able to create a digital clock and tinker with this and that, but now I'm trying to make a basic UI for a derpy game and my timer doesn't work.
First - what I'm trying to accomplish: A simple decrementing timer from 60 seconds (*clock style (mm:ss)).
Second, here's what I have:
public partial class Form1 : Form
{
private int counter = 60;
public Form1()
{
InitializeComponent();
label1.Text = TimeSpan.FromMinutes(1).ToString("m\\:ss");
}
private void pictureBox2_Click(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
if (counter == 0)
{
timer1.Stop();
label1.Text = counter.ToString();
MessageBox.Show("Time's Up!!");
}
}
private void label1_Click(object sender, EventArgs e)
{
var startTime = DateTime.Now;
var counter = (TimeSpan.FromMinutes(1)).ToString("m\\:ss");
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000;
timer1.Start();
label1.Text = counter.ToString();
}
}
Appreciate the feedback and knowledge!
From the codes that I see, your timer is working but you are not updating it in each count, you are updating when the timer finishes -
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
if (counter == 0)
{
timer1.Stop();
label1.Text = counter.ToString(); // *** Look here
MessageBox.Show("Time's Up!!");
}
}
You should update the timer in each tick, so take the update label code out of the if block -
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
label1.Text = counter.ToString(); // should work
if (counter == 0)
{
timer1.Stop();
MessageBox.Show("Time's Up!!");
}
}
and also reset the counter in each cycle -
private void label1_Click(object sender, EventArgs e)
{
var startTime = DateTime.Now;
var counter = (TimeSpan.FromMinutes(1)).ToString("m\\:ss");
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000;
timer1.Start();
label1.Text = counter.ToString();
this.counter = 60
}
NOTE: I am really not sure if this code will throw any access
violation error, due to updating the UI in a different thread or not.
If so, then you have to use async/await or events/delegates to
update UI.
Let me know, if this throws error, then I will give you the async/await version.
This works fine for me. I would give progress updates as the time is countdown to show that it is working. For example, if you did this in label, you could do something like the following:
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
label1.Text = counter.ToString();
if (counter == 0)
{
timer1.Stop();
MessageBox.Show("Time's Up!!");
}
}
Notice that the label1.Text = counter.ToString(); line has been moved before the counter == 0 check, so that it is able to provide feedback for all counter values.
As well, you may accidentally launch several timer1 instances if you do not keep track of how many you spawn using new Timer(). There are various ways to do this, but you could simply check whether timer1 already exists and counter == 0 before creating a new instance. You could perform this check as a guard clause (ie. return if either of those conditions are matched).
private void label1_Click(object sender, EventArgs e)
{
var startTime = DateTime.Now;
if (timer1 == null || (timer1 != null && counter == 0)) return;
counter = (TimeSpan.FromMinutes(1)).ToString("m\\:ss");
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000;
timer1.Start();
label1.Text = counter.ToString();
}
If you want this countdown to start automatically, you can put this directly into the constructor, or put it into another method and call it from the constructor like so:
public Form1()
{
InitializeComponent();
StartCountdown();
}
private void StartCountdown()
{
var startTime = DateTime.Now;
/* the rest of your original label1_Click code goes here ... */
}

Refreshing a chart control

This one is driving me a bit crazy. Any help gratefully received. It's a simple program to receive temperature data from an Arduino based temp sensor, and display it in a graph control on a form. The program works fine, and parses the temp data frame a treat. However..... the graph object doesn't refresh, and the whole point is to show the data over time. I thought that the chart1.DataBind command that I put in forced a refresh. I am using Visual Studio 2013 Express. Any thoughts as to what I am doing wrong very much appreciated.
// Start of program.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace serial_port_with_events_attempt_4
{
public partial class Form1 : Form
{
string RxString;
int RxRead;
int i;
int RxDec1;
int RxDec2;
int RxDec3;
float RxFloat;
float RxFloat2;
string locnString;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM8";
serialPort1.BaudRate = 9600;
serialPort1.Open();
if (serialPort1.IsOpen)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
textBox1.ReadOnly = false;
}
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
textBox1.ReadOnly = true;
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DisplayText));
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void DisplayText(object sender, EventArgs e)
{
if (RxRead == 126)
{
textBox1.AppendText(Environment.NewLine);
i = 0;
}
if (i< 23)
{
if (i == 7)
{
if (RxRead == 51) // 51 in this position means that the temp sensor is the one in the wooden box
{
textBox1.AppendText("Temperature in Nick's office = ");
locnString = ("Nick's office");
}
}
if (i == 17)
{
RxDec1 = RxRead - 48; // Read the tens unit
}
if (i == 18)
{
RxDec2 = RxRead - 48; // Read the units
}
if (i == 20)
{
RxDec3 = RxRead - 49; // read the decimal
}
if (i == 22)
{
RxFloat = ((RxDec1 * 10) + RxDec2);
RxFloat2 = RxDec3;
RxFloat2 = RxFloat2 / 10;
RxFloat = RxFloat + RxFloat2;
RxString = RxFloat.ToString();
if (RxFloat < 30 && RxFloat >20)
{
// Put the value in the main text box if it is not corrupt, (checking if the range is reasonable
textBox1.AppendText(RxString); // Frig about to get the reads in the right format and added together
// Add a new line into the temperature database
temperature1DataSetTableAdapters.Temp1TableAdapter temp1tableadapter = new temperature1DataSetTableAdapters.Temp1TableAdapter();
temp1tableadapter.Insert(DateTime.Now, RxFloat, locnString);
}
// Delete any old data.
temperature1DataSetTableAdapters.TempTableAdapter temp2tableadapter = new temperature1DataSetTableAdapters.TempTableAdapter();
temp2tableadapter.DeleteTempQuery();
// The above two lines work, but I need to amend to select on date TODO
chart1.DataBind();
}
}
i=i+1;
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'temperature1DataSet.Temp' table. You can move, or remove it, as needed.
this.tempTableAdapter.Fill(this.temperature1DataSet.Temp);
}
}
}
Cheers,
Nick James

How to do a 30 minute count down timer

I want my textbox1.Text to countdown for 30 minutes. So far I have this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Timer timeX = new Timer();
timeX.Interval = 1800000;
timeX.Tick += new EventHandler(timeX_Tick);
}
void timeX_Tick(object sender, EventArgs e)
{
// what do i put here?
}
}
However I'm now stumped. I checked Google for answers but couldn't find one matching my question.
Here's a simple example similar to the code you posted:
using System;
using System.Windows.Forms;
namespace StackOverflowCountDown
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.Text = TimeSpan.FromMinutes(30).ToString();
}
private void Form1_Load(object sender, EventArgs e) { }
private void textBox1_TextChanged(object sender, EventArgs e) { }
private void button1_Click(object sender, EventArgs e)
{
var startTime = DateTime.Now;
var timer = new Timer() { Interval = 1000 };
timer.Tick += (obj, args) =>
textBox1.Text =
(TimeSpan.FromMinutes(30) - (DateTime.Now - startTime))
.ToString("hh\\:mm\\:ss");
timer.Enabled = true;
}
}
}
Easiest thing you can do, is use a 1 minute timer:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace countdowntimer
{
public partial class Form1 : Form
{
private Timer timeX;
private int minutesLeft;
public Form1()
{
InitializeComponent();
timeX = new Timer(){Interval = 60000};
timeX.Tick += new EventHandler(timeX_Tick);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
minutesLeft=30;
timeX.Start();
}
void timeX_Tick(object sender, EventArgs e)
{
if(minutesLeft--<=0)
{
timeX.Stop();
// Done!
}
else
{
// Not done yet...
}
textBox1.Text = minutesLeft + " mins remaining";
}
}
}
If all you want to do is set the value of your Texbox to count down from 30 Minutes. You will first need to change your timer interval to something smaller than 30Minutes. Something like timeX.Interval = 1000; which will fire every second. then set up your event like so:
int OrigTime = 1800;
void timeX_Tick(object sender, EventArgs e)
{
OrigTime--;
textBox1.Text = OrigTime/60 + ":" + ((OrigTime % 60) >= 10 ? (OrigTime % 60).ToString() : "0" + OrigTime % 60);
}
Also in your button click, you must add the following line: timeX.Enabled = true; In order to start the timer.
Your code will only get one event fired, once the 30 minutes has passed. In order to keep updating your UI continuously you'll have to make the events more frequent and add a condition inside the event handler to tell the count-down to stop once 30 minutes has passed.
You can do the time calculations easily by using TimeSpan and DateTime.
You'll also want to make sure your UI code runs on the UI thread, hence the Invoke.
timeX.Interval = 500;
...
TimeSpan timeSpan = TimeSpan.FromMinutes(30);
DataTime startedAt = DateTime.Now;
void timeX_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - startedAt)<timeSpan){
Invoke(()=>{
TimeSpan remaining = timeSpan - (DateTime.Now - startedAt);
textBox.Text = remaining.ToString();
});
} else
timeX.Stop();
}
try this hope this will work for u
set timer interval=1000
minremain=1800000; //Should be in milisecond
timerplurg.satrt();
private void timerplurg_Tick(object sender, EventArgs e)
{
minremain = minremain - 1000;
string Sec = string.Empty;
string Min = string.Empty;
if (minremain <= 0)
{
lblpurgingTimer.Text = "";
timerplurg.Stop();
return;
}
else
{
var timeSpan = TimeSpan.FromMilliseconds(Convert.ToDouble(minremain));
var seconds = timeSpan.Seconds;
var minutes = timeSpan.Minutes;
if (seconds.ToString().Length.Equals(1))
{
Sec = "0" + seconds.ToString();
}
else
{
Sec = seconds.ToString();
}
if (minutes.ToString().Length.Equals(1))
{
Min = "0" + minutes.ToString();
}
else
{
Min = minutes.ToString();
}
string Totaltime = "Purge Remaing Time: " + Min + ":" + Sec;
lblpurgingTimer.Text = Totaltime;
}
}

Categories

Resources