I've started a course of c# and I cant get my timer to run. Its probably pretty simple and I've just missed something here. Basically I have a button to start and stop a traffic light sequence. I wanted an interval of 1 second. Heres what I've written. It doesn't work as intended when I press start. Thank you.
}
public int counter = 0;
private void rbStart_CheckedChanged(object sender, EventArgs e)
{
counter++;
if (counter == 1)
{
pbRed.Visible = true;
pbAmber.Visible = false;
pbGreen.Visible = false;
}
else if (counter == 2)
{
pbRed.Visible = true;
pbAmber.Visible = true;
pbGreen.Visible = false;
}
else if (counter == 3)
{
pbRed.Visible = false;
pbAmber.Visible = false;
pbGreen.Visible = true;
}
else if (counter == 4)
{
pbRed.Visible = false;
pbAmber.Visible = true;
pbGreen.Visible = false;
}
else if (counter == 5)
{
pbRed.Visible = true;
pbAmber.Visible = false;
pbGreen.Visible = false;
}
else
{
counter = 0;
}
}
private void rbStop_CheckedChanged(object sender, EventArgs e)
{
pbRed.Visible = false;
pbAmber.Visible = false;
pbGreen.Visible = false;
}
private void Form1_Load(object sender, EventArgs e)
{
Light_timer.Tick += new EventHandler(rbStart_CheckedChanged);
Light_timer.Interval = 1000;
}
}
The Interval property merely designates how much time elapses between Tick events. You might want to consider a separate variable to track the "state" of your light, and then "bump" that variable with each "Tick" in your event handler. Then just adjust your UI elements to reflect the proper state of your traffic light. You might have a "stopped" state, a "careful" state, and a "green" state, and your light might just "cycle" between each on on each tick. I'll leave you to write the details as it appears to be an assignment. Good luck.
I think you probably misinterpreted how the Timer works. The Timer.Tick Event fires when the Interval has elapsed. Interval is used by the Timer to determine how long to run between ticks. Its value is never changed by the Timer. In fact, a System.Windows.Forms.Timer has no way to retrieve elapsed time, which means you'll need a state tracking mechanism of your own that doesn't depend on that. Take a good look at the example on the page I referenced above and make sure you understand how it works, then give it another shot.
Related
I have several buttons that I want turned off/on at different times. I put these into a function for simplicity. Enabling the buttons is called by a BackgroundWorker so that I can update a camera view at the same time as listening to a Serial port for an 'enable' signal. Disabling the controls is called by the button click, while enable is handled by the BackgroundWorker (it watches for the Serial port signal). All buttons re-enable, except for the first one listed in enableControls();. If I change the order of enableControls() then the button at top is left disabled. What is causing this? I would think that either all buttons or no buttons would be re-enabled.
private void btnLeft_Click(object sender, EventArgs e) // All buttons are similar, just different output to port
{
disableControls();
hardWorker.RunWorkerAsync();
int stepSize = Convert.ToInt32(ddStepSize.Text);
string outString;
if (moveSampHome == false)
{
outString = "#MOVER" + stepSize;
posX = posX - RcDrawSlide.Width * stepSize / (1000 * Convert.ToInt32(slideSizeX));
}
else { outString = "#MSMPR" + stepSize; }
port.Write(outString + "\n");
}
private void hardWorker_DoWork(object sender2, DoWorkEventArgs f)
{
arduinoIn = "0";
for (int i = 0; i == 0;)
{
if (arduinoIn != null)
{
if (arduinoIn.Contains("1"))
{
i = 1;
arduinoIn = "0";
}
}
}
port.Write("1");
}
private void hardWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
enableControls();
}
private void enableControls()
{
btnBack.Enabled = true; // Swap this for any other button - that one will not be enabled.
btnForward.Enabled = true;
btnLeft.Enabled = true;
btnRight.Enabled = true;
}
private void disableControls()
{
btnBack.Enabled = false;
btnForward.Enabled = false;
btnLeft.Enabled = false;
btnRight.Enabled = false;
}
If I add a button that runs enableControls() on click everything is reenabled, so I know this is due to having it run from a BackgroundWorker. I think that BackgroundWorker is necessary, though. I'm just unsure why it's only the first btn.Enabled = true; that doesn't work. Is there a workaround for this?
For hardWorker_DoWork() try something more like:
private void hardWorker_DoWork(object sender2, DoWorkEventArgs f)
{
arduinoIn = "0";
while (arduino == null || !arduinoIn.Contains("1")) {
System.Threading.Thread.Sleep(0); // or try a SMALL number like 50!
}
arduinoIn = "0";
port.Write("1");
}
Is it possible the buttons are being enabled again when data is received on the port? You haven't shown any code relating to that side...
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'm a C# newbie_and in programming in general_ and Ι'm trying to build a math quiz app with a countdown timer.
I generate an equation each time the user clicks the start button and I give him a max 60 seconds to answer. The user answers -whether his answer is wrong or right doesn't matter_ and can he/she can click again for a new equation. So I want the timer to reset each time the user is shown a new random equation. So far I've only managed to reset this when the 60sec timespan elapses but even that is not working properly, sometimes it displays 59 or 58 secs instead of 60.
So far reading other questions has't helped me much and the timer confuses me. I also accept suggestions to make my code simpler and more elegant.
Here is my code:
EquationView.xaml.cs
public sealed partial class EquationView : Page
{
DispatcherTimer timer = new DispatcherTimer();
int tick = 60;
int result;
public EquationView()
{
this.NavigationCacheMode = NavigationCacheMode.Enabled;
this.InitializeComponent();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
// Once clicked then disabled
startButton.IsEnabled = false;
// Enable buttons required for answering
resultTextBox.IsEnabled = true;
submitButton.IsEnabled = true;
var viewModel = App.equation.GenerateEquation();
this.DataContext = viewModel;
result = App.equation.GetResult(viewModel);
timer.Interval = new TimeSpan(0, 0, 0, 1);
//timer.Tick += new EventHandler(timer_Tick);
timer.Tick += timer_Tick;
timer.Start();
DateTime startTime = DateTime.Now;
// Reset message label
if (message.Text.Length > 0)
{
message.Text = "";
}
// Reset result text box
if (resultTextBox.Text.Length > 0)
{
resultTextBox.Text = "";
}
}
private void timer_Tick(object sender, object e)
{
Countdown.Text = tick + " second(s) ";
if (tick > 0)
tick--;
else
{
Countdown.Text = "Times Up";
timer.Stop();
submitButton.IsEnabled = false;
resultTextBox.IsEnabled = false;
startButton.IsEnabled = true;
tick = 60;
}
}
private void submitButton_Click(object sender, RoutedEventArgs e)
{
timer.Stop();
submitButton.IsEnabled = false;
resultTextBox.IsEnabled = false;
if (System.Text.RegularExpressions.Regex.IsMatch(resultTextBox.Text, "[^0-9]"))
{
MessageDialog msgDialog = new MessageDialog("Please enter only numbers.");
msgDialog.ShowAsync();
resultTextBox.Text.Remove(resultTextBox.Text.Length - 1);
//Reset buttons to answer again
submitButton.IsEnabled = true;
resultTextBox.IsEnabled = true;
timer.Start();
}
else
{
try
{
int userinput = Int32.Parse(resultTextBox.Text);
if (userinput == result)
{
message.Text = "Bingo!";
App.player.UpdateScore();
startButton.IsEnabled = true;
}
else
{
message.Text = "Wrong, sorry...";
startButton.IsEnabled = true;
}
}
catch (Exception ex)
{
MessageDialog msgDialog = new MessageDialog(ex.Message);
msgDialog.ShowAsync();
submitButton.IsEnabled = true;
resultTextBox.IsEnabled = true;
timer.Start();
}
}
}
It seems to me that you have at least two significant problems here. One is that your timer will likely give the user more than 60 seconds, due to the inaccuracy in the Windows thread scheduler (i.e. each tick will occur at slightly more than 1 second intervals). The other (and more relevant to your question) is that you don't reset the tick value to 60 except when the timer has elapsed.
For the latter issue, it would be better to simply reset your countdown value when you start the timer, rather than trying to remember everywhere that you stop it.
To fix that and the first issue, get rid of the tick field altogether and change your code to look more like this:
static readonly TimeSpan duration = TimeSpan.FromSeconds(60);
System.Diagnostics.Stopwatch sw;
private void startButton_Click(object sender, RoutedEventArgs e)
{
// Once clicked then disabled
startButton.IsEnabled = false;
// Enable buttons required for answering
resultTextBox.IsEnabled = true;
submitButton.IsEnabled = true;
var viewModel = App.equation.GenerateEquation();
this.DataContext = viewModel;
result = App.equation.GetResult(viewModel);
sw = System.Diagnostics.Stopwatch.StartNew();
timer.Interval = new TimeSpan(0, 0, 0, 1);
timer.Tick += timer_Tick;
timer.Start();
// Reset message label
if (message.Text.Length > 0)
{
message.Text = "";
}
// Reset result text box
if (resultTextBox.Text.Length > 0)
{
resultTextBox.Text = "";
}
}
private void timer_Tick(object sender, object e)
{
if (sw.Elapsed < duration)
{
Countdown.Text = (int)(duration - sw.Elapsed).TotalSeconds + " second(s) ";
}
else
{
Countdown.Text = "Times Up";
timer.Stop();
submitButton.IsEnabled = false;
resultTextBox.IsEnabled = false;
startButton.IsEnabled = true;
}
}
This way, it won't matter exactly when the tick event happens, the code will still correctly compute the actual time remaining and use that for the display and to tell whether the time is up.
Am new to C# and i need your help on this, I want to display one character at a time in a textbox this is my code
private void timer1_Tick(object sender, EventArgs e)
{
int i = 0; //why does this don't increment when it ticks again?
string str = "Herman Lukindo";
textBox1.Text += str[i];
i++;
}
private void button1_Click(object sender, EventArgs e)
{
if(timer1.Enabled == false )
{
timer1.Enabled = true;
button1.Text = "Stop";
}
else if(timer1 .Enabled == true )
{
timer1.Enabled = false;
button1.Text = "Start";
}
}
why does this don't increment when it ticks again?
Because your variable i is local to your event. You need to define it at class level.
int i = 0; //at class level
private void timer1_Tick(object sender, EventArgs e)
{
string str = "Herman Lukindo";
textBox1.Text += str[i];
i++;
}
On exit of your event, variable i becomes out of scope and looses its value. On the next event it is considered a new local variable with the initialized value of 0.
Next, you should also look for cross threaded exception. Since your TextBox is not getting updated on the UI thread.
The issue with you code is that you are assigning i = 0 with every tick, so it will always be 0 everytime it is used. I would suggest using a class level variable for this.
However, using a variable at class level means you are going to need to reset to 0 at some point, probably each time you start the timer.
A further point is that you are going to want to validate the tick event to ensure you don't try to access an index that doesn't exist (IndexOutOfRangeException). For this I would recommend automatically stopping the timer once the last letter has been printed.
With all that in mind, here is my suggested code:
int i = 0;// Create i at class level to ensure the value is maintain between tick events.
private void timer1_Tick(object sender, EventArgs e)
{
string str = "Herman Lukindo";
// Check to see if we have reached the end of the string. If so, then stop the timer.
if(i >= str.Length)
{
StopTimer();
}
else
{
textBox1.Text += str[i];
i++;
}
}
private void button1_Click(object sender, EventArgs e)
{
// If timer is running then stop it.
if(timer1.Enabled)
{
StopTimer();
}
// Otherwise (timer not running) start it.
else
{
StartTimer();
}
}
void StartTimer()
{
i = 0;// Reset counter to 0 ready for next time.
textBox1.Text = "";// Reset the text box ready for next time.
timer1.Enabled = true;
button1.Text = "Stop";
}
void StopTimer()
{
timer1.Enabled = false;
button1.Text = "Start";
}
I'm trying to implement the code that will loop current song countless times.
That's my code:
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 8) // media ended
{
if (repeat)
{
axWindowsMediaPlayer1.Ctlcontrols.currentPosition = 0;
//axWindowsMediaPlayer1.Ctlcontrols.previous();
//axWindowsMediaPlayer1.Ctlcontrols.playItem(axWindowsMediaPlayer1.Ctlcontrols.currentItem);
}
}
}
setting currentPosition = 0 is working fine if I debug the code on the next line.
But after debug - new event is triggered(event 9(Transitioning) followed by event 3(Playing)) and the next song starts to play!
how do I prevent this from happening?
basically that is what happening right now:
event 8 triggered (Media End)
set position 0
event 9 triggered (Transitioning)
event 3 triggered (Playing)
Edit: after messing around with my code I have finally managed to break the chain of Event changes.
public bool ended = false;
public WMPLib.IWMPMedia latest_song;
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (ended)
{
axWindowsMediaPlayer1.Ctlcontrols.playItem(latest_song);
ended = false;
return;
}
if (e.newState == 8) // media ended
{
if (repeat)
{
ended = true;
latest_song = axWindowsMediaPlayer1.Ctlcontrols.currentItem;
}
}
}
I don't know if the code can get any better than this..
bool ended = false;
bool skipnext = false;
bool skipnextnext = false;
bool skipextra = false;
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (ended)
{
skipnext = true;
ended = false;
axWindowsMediaPlayer1.Ctlcontrols.playItem(latest_song);
return;
}
if (e.newState == 6) // buffering
{
skipextra = true;
}
if (e.newState == 8) // media ended
{
if (repeat)
{
if (currect_album.Songs.Count < 2) { return; }
ended = true;
latest_song = current_song;
return;
}
}
else if (e.newState == 3) // playing
{
// these "skips" are necessary for scenario: "repeat: on", "click: next"
if (skipnext) { skipnext = false; skipnextnext = true; return; }
if (skipnextnext) { skipnextnext = false; return; }
// Buffering adds 1 more skip! Ask Microfost why ;)
if (skipextra) { skipextra = false; return; }
current_song = axWindowsMediaPlayer1.Ctlcontrols.currentItem;
// your stuff
}
}
the first solution worked fine for half a day ;)
the second solution worked for "repeat", but did not work in case if user clicked "next"
the third and final (I hope) solution finally works in situations when "repeat" is needed, plus it skips the song if "next/prev" command is triggered!
the fourth edition! added extra "skip" if buffering kicked in.. Buffering messed up my code a bit, but now it's all working. Additionally, I've added "1 song in a playlist" checker.
P.S. Microsoft coders - if you see this post - please, add "on_next" and "on_previous" status! Thanks