I'm new to C# and I'm trying to make a custom chronometer that is composed of two labels (label1 and label2) that display time strings (time and time0/time1) and one button (pause/play) that changes its text from pause to play and viceversa on each click. Label1 shows time that is a string var maked by datetime.now (hhmmss), label2 shows time0 and after clicking on the button "pause" and again on "play" it will shows time1 (time 1 is calculated by the formula below).
It does the following:
get system datetime.now (hhmmss), saves it in time string and shows it in label1
pushing the button pause, saves the value of time in another string time0 and shows it stopped in label2
pushing the button play, starts the time of label2 (time1) that's not synchronized with the time of label1
To calculate time1 I would like to use this formula:
time1 = DateTime.Now - ((difference between DateTime.Now and time0) - 1 second)
I'm stucked on the 3rd point because I don't know how to do the time difference between two strings and use the new time time1 as text for label2 and next clicks.
This is my actual code, any help to complete it is appreciate, thank you.
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 WindowsFormsApplication1
{
public partial class Form1 : Form
{
//time0
public int hh = 0;
public int mm = 0;
public int ss = 0;
//time
public string time = "";
public string time0 = "";
public bool IsPause = true;
public Timer t = new Timer();
public Form1()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
//timer interval
t.Interval = 1000; //in millisecondi
t.Tick += new EventHandler(this.t_Tick);
//start timer form loads
t.Start(); //questo userĂ il metodo t_Tick()
}
//timer eventhandler
private void t_Tick(object sender, EventArgs e)
{
//get current time
hh = DateTime.Now.Hour;
mm = DateTime.Now.Minute;
ss = DateTime.Now.Second;
//padding leading zero
if(hh < 10)
{
time += "0" + hh;
}
else
{
time += hh;
}
time += ":";
if(mm < 10)
{
time += "0" + mm;
}
else
{
time += mm;
}
time += ":";
if (ss < 10)
{
time += "0" + ss;
}
else
{
time += ss;
}
//update labels
label1.Text = time;
if (IsPause == false) label2.Text = time0;
else label2.Text = time;
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "pause")
{
IsPause = false;
button1.Text = "play";
time0 = label1.Text;
}
else
{
IsPause = true;
button1.Text = "pause";
}
}
}
}
It sounds as if you are best saving the time in the controls as well as the time as a string. The Tag property is there for that purpose. See https://msdn.microsoft.com/en-us/library/system.windows.forms.control.tag%28v=vs.110%29.aspx
So, for example, if you set the DateTime you are using into label2.Tag to the same time as you format it as text in label2.Text then you can refer to it as a DateTime. Then when you need to calculate from it you can use
DateTime.Subtract - see https://msdn.microsoft.com/en-us/library/8ysw4sby%28v=vs.110%29.aspx
to determine the elapsed time.
So, to refer this to your code, wherever you have code like this, where time is the string you have created from a DateTime instance:
label1.Text = time;
you also need to set the time like this (DateTime.Now is an example, you should chose whatever you used to format the time string):
label1.Tag = DateTime.Now
Then later, when you want to know the time in label1, do this:
DateTime t = (DateTime)label1.Tag
Related
Dispose isn't working in my code for some reason. When i hit the reset button, and then start again, it won't start the timer over. I've tried disabling and reenablinig enabled(), but it still didn't work.
Here's my code:
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 WindowsFormsApp1
{
public partial class StopWatch : Form
{
bool reSet = false;
bool stopped = true;
public StopWatch()
{
InitializeComponent();
}
private void startStop_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
if (stopped == true)
{
timer1.Start();
stopped = false;
}
else
{
timer1.Stop();
stopped = true;
}
}
private void reset_Click(object sender, EventArgs e)
{
timer1.Dispose();
txtBox.Text = "";
reSet = true;
stopped = true;
}
int i = 0;
private void timer1_Tick(object sender, EventArgs e)
{
txtBox.Text = i.ToString();
i++;
}
}
}
Forget the timer for now, just make a stopwatch:
DateTime startTime = DateTime.MinValue; //it's reset
StartButton_Click(...){
startTime = DateTime.Now;
}
StopButton_Click(...){
MessageBox.Show("counted secs: " + (DateTime.Now - startTime).TotalSeconds);
}
That's a stopwatch
Now let's make it look like it runs. Add a label to the Form. Add a timer to the form, set it's interval to 100, enable it and put a tick event:
Timer_Tick(...){
StopWatchLabel.Text = startTime == DateTime.MinValue ? "00:00:00.000" : (DateTime.Now - startTime).ToString();
}
Now you can get into the minutiae of adding a reset button (set startTime to MinValue) starting and stopping the timer (no point updating a label to 00:00 ten times a second, but no harm in it either) but hopefully this proves that the timer is not (and should not) be part of the stopwatch function of measuring the passage of time. The timer doesn't need messing with/disposing etc. It's purely to update a label with the period that has passed since your start time
I wrote some code to create a reminder. It should warn me through a notification when it's 10 am. To make this possible I created a DateTime object as DateTime.Now to get local time, and I used a timer to check every minute if it was the same time I wanted to be warned. The problem is that my application notify me only when form loads, but it doesn't when the time comes and the app is already running.
I'll leave you the code below. Thanks in advance.
public partial class Form1 : Form
{
NotifyIcon notify;
DateTime now;
public Form1()
{
InitializeComponent();
notify = new NotifyIcon()
{
Visible = true,
Icon = Properties.Resources.icon,
BalloonTipTitle = this.Text
};
now = DateTime.Now;
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
private void notification()
{
while(true)
{
if (now.Hour.Equals(10) && now.Minute.Equals(30))
{
notify.BalloonTipText = "It's 10:30 am";
notify.ShowBalloonTip(3000);
timer1.Stop();
notify.Dispose();
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
notification();
}
}
Remove while(true) loop from notification. You have tick timer which will call notification regularly - and now you check the time infinitely after first tick.
now must be assigned on every tick, not at startup.
:
private void notification()
{
DateTime now = DateTime.Now;
if (now.Hour == 10 && now.Minute == 30)
{
notify.BalloonTipText = "It's 10:30 am";
notify.ShowBalloonTip(3000);
timer1.Stop();
}
}
At the minute i have a match picture game in c# windows forms with a timer that stops when all matches are complete. I am wondering how do i save the time taken and the name that is entered using btn_player in a text file. The text file is stored at (#"E:\Match Picture\Public\Files\playerdetails.txt");
using System.Windows.Forms;
using System.Threading;
using System.IO;
namespace Match_Picture
{
public partial class Form1 : Form
{
string Temp_Tag = "";
int Number_of_Images = 0;
Label Clicked_Picture = new Label();
Label Temp_Pic = new Label();
int Num_Correct = 0;
public Form1()
{
InitializeComponent();
}
private void Picture_Click(object sender, EventArgs e)
{
Clicked_Picture = (Label)sender;
Number_of_Images++;
if (Number_of_Images < 3)
{
Clicked_Picture.Text = Clicked_Picture.Tag.ToString();
if (Number_of_Images == 1)
{
Temp_Tag = Clicked_Picture.Tag.ToString();
Temp_Pic = Clicked_Picture;
}
else
{
if (Temp_Tag != Clicked_Picture.Tag.ToString())
{
tmr_Delay.Enabled = true;
scorecounter.Text = Convert.ToString(Convert.ToInt32(scorecounter.Text) - 20);
}
else
{
Num_Correct++;
scorecounter.Text = Convert.ToString(Convert.ToInt32(scorecounter.Text) + 50);
lbl_Matches.Text = Num_Correct.ToString();
if (Num_Correct == 8)
{
tmr_1.Stop();
MessageBox.Show("Congratulations, all matches complete");
MessageBox.Show("Number of seconds to match all the pictures: " + i);
this.Close();
}
}
Number_of_Images = 0;
}
}
}
private void tmr_Delay_Tick(object sender, EventArgs e)
{
Clicked_Picture.Text = "R";
Temp_Pic.Text = "R";
tmr_Delay.Enabled = false;
}
int i = 0;
private void timer1_Tick(object sender, EventArgs e)
{
i++;
lbl_time.Text = i.ToString() ;
}
private void btn_player_Click(object sender, EventArgs e)
{
}
You can use the StreamWriter class in order to do what you need.
using (StreamWriter writer = new StreamWriter(#"E:\Match Picture\Public\Files\playerdetails.txt"))
{
writer.WriteLine("") // This is where you will write what you want to that file
}
As MethodMan, you can use EndTime - StartTime, and any other conversions necessary in order to get it in the format you want (minutes, seconds, etc).
This code will simply write to the text file. It will create it if it does not exists, and it will overwrite the file if it does exist. You need to do the proper checks to make sure that you don't overwrite it, or you can use
new StreamWriter(#"E:\Match Picture\Public\Files\playerdetails.txt", true)
if you want to append the file instead of overwriting. Full documentation of the StreamWriter class can be found here http://msdn.microsoft.com/en-us/library/system.io.streamwriter%28v=vs.110%29.aspx
As an aside, if you're trying to keep records of high score, you should also look into the StreamReader class. You can read in the file into a dictionary of Player and Time, and check to see if a player already exists in the file and only adjust their score if it beats their best score.
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
{
int randumnum1;
public Form1()
{
InitializeComponent();
}
public int randumnum()
{
Random r = new Random();
int randumnum = r.Next(15, 30);
return randumnum;
}
private void button2_Click(object sender, EventArgs e)
{
randumnum1 = randumnum();
string strrandumnum = randumnum1.ToString();
label4.Text = strrandumnum;
button2.Text = "New Game";
}
private void button1_Click(object sender, EventArgs e)
{
Random r = new Random();
int computer = r.Next(1, 4);
String strrandumnum;
if (((Convert.ToInt32(textBox1.Text)) < 1) || ((Convert.ToInt32(textBox1.Text)) > 3))
{
MessageBox.Show("Invalid input. Remember you can enter numbers between 1 and 3 only", "Error");
textBox1.Text = "";
}
else if (Convert.ToInt32(textBox1.Text) == 1)
{ randumnum1 -= 1;
strrandumnum = randumnum1.ToString();
label4.Text = strrandumnum;
textBox1.Text = "";
}
else if (Convert.ToInt32(textBox1.Text) == 2)
{
randumnum1 -= 2;
strrandumnum = randumnum1.ToString();
label4.Text = strrandumnum;
textBox1.Text = "";
}
else if (Convert.ToInt32(textBox1.Text) == 3)
{
randumnum1 -= 3;
strrandumnum = randumnum1.ToString();
label4.Text = strrandumnum;
textBox1.Text = "";
}
//I want a 3 second delay right here but nothing seems to work. I tried the
//thread sleep but it skipped all the other if statements and was messed up.
randumnum1 -= computer;
strrandumnum = randumnum1.ToString();
label4.Text = strrandumnum;
}
You say in your comment that you tried Thread.Sleep, and you're right: that will pause the currently executing thread for 3 seconds, which means your UI will stop responding for those 3 seconds.
What you might try instead is using a System.Windows.Forms.Timer, which can be started in your code where you want the delay to happen. It will then fire an event when your delay is complete, and your post-delay code should go in the event handler. This way, your delay can happen without affecting the UI.
I guess one way would be Thread.Sleep(3000);. There are a number of ways to do what you want, but based on the code you've provided, that should suffice. Place it where you want the delay.
I'm creating a countdown timer that allows the user to choose a valid time, and once the countdown reaches zero, it plays a sound.
I've instantiated a timer from the System.Timers namespace and set its Interval to 1 second. I convert the user-specified time to seconds, and decrement that value by 1 every time the Timer.Elapsed function hits. Once it reaches zero, that means the countdown has reached zero which means it's time to play the sound.
However, whenever it doesn't reach zero, I decrement the time value by 1 and I also want to increment the ProgressBar by using the progressbar.Increment function.
Unfortunately, whenever I do this, it gives me an exception having to do with multithreading issues. I know what is wrong, but I am not sure how to fix it. Do I need to start the timer.Elapsed function on a new thread?
The error is:
Cross-thread operation not valid: Control 'CountdownProgress' accessed
from a thread other than the thread it was created on.
Also, any tips on better programming habits are welcome as well.
Many thanks!
Here is the code:
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;
using System.Timers;
using System.Media;
using System.Diagnostics;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form_CDA : Form
{
public Form_CDA()
{
InitializeComponent();
}
private bool m_CountdownActive; // declare global variables and instantiate timer.
private bool m_Cancelled;
public decimal seconds;
public decimal minutes;
public decimal hours;
public decimal time;
public System.Timers.Timer timer = new System.Timers.Timer();
private void Form_CDA_Load(object sender, EventArgs e)
{
m_Cancelled = false;
timer.AutoReset = false;
timer.Interval = 0;
m_CountdownActive = false;
richTextBox1.Text = "Hello, please select an hour between 0 and 100, a minute between 0 and 59, and a second between 0 and 59. The countdown timer will play a sound when finished.";
btn_Cancel.Enabled = false;
seconds = 0;
minutes = 0;
hours = 0;
time = 0;
m_StatusBar.Text = "Program properly loaded, waiting for user input"; // initialize variables.
}
private void btn_SetCountdown_Click(object sender, EventArgs e)
{
seconds = numUpDown_Seconds.Value;
minutes = numUpDown_Minutes.Value;
hours = numUpDown_Hours.Value;
time = (hours * 3600) + (minutes * 60) + seconds; // calculate the total time in seconds.
if (time != 0) // if time is not zero, start timer and set up event handler timer.elapsed.
{
timer.Interval = 1000;
timer.AutoReset = true;
timer.Start();
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
CountdownProgress.Maximum = (int)time;
CountdownProgress.Minimum = 0;
CountdownProgress.Value = 0;
}
else
{
m_StatusBar.Text = "Invalid selection of times. Try again.";
return;
}
DateTime dt = DateTime.Now;
dt.AddSeconds((double)time);
Label_Countdown.Text = "Finishing time: " + dt.ToString(); // display end time to user.
m_CountdownActive = true;
btn_Cancel.Enabled = true;
btn_SetCountdown.Enabled = false;
numUpDown_Hours.Enabled = false;
numUpDown_Minutes.Enabled = false;
numUpDown_Seconds.Enabled = false; // disable controls.
m_Cancelled = true;
m_StatusBar.Text = "Timer set to " + numUpDown_Hours.Value.ToString() + " hours, " + numUpDown_Minutes.Value.ToString() + " minutes, " + numUpDown_Seconds.Value.ToString() + " seconds.";
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (time == 0)
{
m_StatusBar.Text = "Countdown Finished";
SoundPlayer soundPlayer = new SoundPlayer(#"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
soundPlayer.Play(); // play sound.
timer.Stop();
return;
}
else
{
time = time - 1;
CountdownProgress.Increment(1); // exception occurs here; multithreading issues.
}
}
private void btn_Cancel_Click(object sender, EventArgs e)
{
// if user wishes to stop the countdown to start a new one.
m_Cancelled = true;
m_CountdownActive = false;
btn_SetCountdown.Enabled = true;
numUpDown_Seconds.Value = 0;
numUpDown_Minutes.Value = 0;
numUpDown_Hours.Value = 0;
numUpDown_Hours.Enabled = true;
numUpDown_Minutes.Enabled = true;
numUpDown_Seconds.Enabled = true;
btn_Cancel.Enabled = false;
m_StatusBar.Text = "Countdown cancelled";
}
}
}
A control can only be accessed within the thread it was created. Therefore use Invoke to execute the given code as a delegate on the main thread, where the control (progressbar) was created.
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (time == 0)
{
m_StatusBar.Text = "Countdown Finished";
SoundPlayer soundPlayer = new SoundPlayer(#"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
soundPlayer.Play(); // play sound.
timer.Stop();
return;
}
else
{
time = time - 1;
Invoke(new Action(() => CountdownProgress.Increment(1)));
}
}
You may want to read http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx