Below is the code I created in attempt to make a timeline controlled by a play/stop button. I use the Timer from the Toolbox to increment time as I progress the timeline using the framesPerSecond. I feel that the timer seems to be a bit in accurate. I was wondering if any had any suggested improvements on controlling the time more accurately? I'm new to c# so bear with me on the coding. If it helps this code is for a larger project which I want to create, and this would be the control for the timeline which will eventually swap through images like a slideshow.
Thanks
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 timelineControls
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timer1.Tick += new EventHandler(timer_Tick); // Every time timer ticks, timer_Tick will be called
}
private void cbPlayStop_CheckedChanged(object sender, EventArgs e)
{
Flipbook();
}
private void numFps_ValueChanged(object sender, EventArgs e)
{
Flipbook();
}
public void Flipbook()
{
bool result = cbPlayStop.Checked;
if (result)
{
cbPlayStop.BackColor = System.Drawing.Color.Red;
cbPlayStop.Text = "Stop";
// increment the counter at a speed of (X) per second
float framerate = (float)1.0 / (float)numFps.Value;
// Timer will tick every 1 seconds (1000 milliseconds)
timer1.Interval = (int)((float)1000 * framerate);
timer1.Enabled = true; // pauses/unpauses
timer1.Start();
}
else
{
cbPlayStop.BackColor = System.Drawing.Color.Green;
cbPlayStop.Text = "Play";
// stop timer from counting
timer1.Stop();
}
}
private int curTime = 0;
void timer_Tick(object sender, EventArgs e)
{
//MessageBox.Show("Tick"); // Alert the user
int hours = DateTime.Now.Hour;
int minutes = DateTime.Now.Minute;
int seconds = DateTime.Now.Second;
int milSeconds = DateTime.Now.Millisecond;
string timeString = hours + " : " + minutes + " : " + seconds + " : " + milSeconds;
bool loopEnabled = cbLoop.Checked;
curTime += 1;
if (loopEnabled)
{
if (curTime > pBarTime.Maximum)
{
curTime = pBarTime.Minimum;
}
}
else
{
if (curTime > pBarTime.Maximum)
{
timer1.Stop();
curTime = pBarTime.Maximum;
}
}
pBarTime.Value = curTime;
label2.Text = timeString;
lbCurTime.Text = curTime.ToString();
}
}
}
You are adding a new Tick event every time you call FlipBook, so yes, it's running multiple times.
Move that declaration to the constructor:
public Form1()
{
InitializeComponent();
timer.Tick += new EventHandler(timer_Tick);
}
In regards to the Timer's capabilities, see MSDN Timer Class
The Windows Forms Timer component is single-threaded, and is limited to an accuracy of 55 milliseconds. If you require a multithreaded timer with greater accuracy, use the Timer class in the System.Timers namespace.
Related
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Extract
{
public partial class LoadingLabel : Label
{
private int TimeToCount = 300;
private int Interval = 1000;
private System.Windows.Forms.Timer _timer;
private int counter = 0;
public LoadingLabel()
{
InitializeComponent();
this.Font = new Font("Arial", 14, FontStyle.Bold);
StartCountDownTimer(Interval, true);
}
public void StartCountDownTimer(int Interval, bool EnableTimer)
{
_timer = new System.Windows.Forms.Timer
{
Interval = Interval,
Enabled = false
};
_timer.Enabled = EnableTimer;
_timer.Tick += (sender, args) =>
{
if (counter == 0)
{
this.Text = ".";
Thread.Sleep(3);
counter++;
}
if(counter == 1)
{
this.Text = "..";
Thread.Sleep(3);
counter++;
}
if(counter == 2)
{
this.Text = "...";
Thread.Sleep(3);
counter = 0;
}
};
}
}
}
The interval is set to 1000 one second.
I want to use the interval so each second it will add another dot starting from one dot to three.
Then in the end when there are three dots start over again from one.
I tried for testing using a Thread.Sleep but it's not working it's showing only the last three dots and that's it.
In the _timer.Tick your ifs are running sequentially.
You could replace 2nd and 3rd ifs with else if or replace your code with the following:
if (counter == 3)
{
this.Text = "";
counter = 0;
}
this.Text += ".";
Thread.Sleep(3);
counter++;
Also you could eliminate the counter field since its value is always equal to the Text.Length.
Try a simple solution:
public Form1()
{
InitializeComponent();
Text = "";
timer = new System.Windows.Forms.Timer
{
Interval = 1000
};
timer.Tick += Timer_Tick;
timer.Start();
}
private void Timer_Tick(object? sender, EventArgs e)
{
if (Text.Contains("..."))
{
Text = "";
}
else
{
Text += ".";
}
}
This timer fires as expected when it is set to 3 seconds, 10 seconds, 60 seconds, 10 minutes, 20 minutes but stops working when set to 30 minutes. It's just a simple app that pops up on my screen to remind me to do various tasks. I've seen posts about instead using System Timers, Threading Timer, and Forms Timer. But, since this particular application is meant to actually interact with a UI, I thought Forms Timer was the way to go. Also, the code seems to work perfectly fine for times lower than 30 minutes.
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
static int thirtyMins = 30 * 60 * 1000;
static int runTime = thirtyMins;
static int minTotal = 0;
public Form1()
{
InitializeComponent();
}
public void updateLabels()
{
label1.Text = "shown " + DateTime.Now.ToString("h:mm:ss tt");
label2.Text = runTime / 1000 + " sec";
label3.Text = "hidden " + minTotal;
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = thirtyMins * 1000;
timer1.Enabled = true;
updateLabels();
Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " Loaded!!");
}
private void timer1_Tick(object sender, EventArgs e)
{
updateLabels();
this.WindowState = FormWindowState.Normal;
this.Activate();
this.Update();
Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " Tick!!");
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
try
{
if (textBox1.Text.Contains("*"))
{
int sec = 1;
String[] split = textBox1.Text.Split('*');
foreach (string s in split)
{
sec *= Int32.Parse(s.Trim());
}
runTime = sec * 1000;
}
else
{
runTime = Int32.Parse(textBox1.Text.Trim()) * 1000;
}
timer1.Interval = runTime;
updateLabels();
}
catch
{
timer1.Interval = thirtyMins;
}
}
private void Form1_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
minTotal++;
updateLabels();
}
}
}
}
I am trying to create a program that shuts down the computer after the entered amount of time (hours, minutes and seconds). Everything works except it doesn't update richTextBox1 at all. Please could someone help with this issue. Thanks in advance.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
namespace ShutdownPC
{
public partial class Form1 : Form
{
public int inputHours = 0;
public int inputMinutes = 0;
public int inputSeconds = 0;
public int totalSeconds = 0;
public int totalMilliseconds = 0;
public int ticks = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Enabled = false;
textBox2.Enabled = false;
textBox3.Enabled = false;
button1.Enabled = false;
// Hours
if (!string.IsNullOrWhiteSpace(textBox1.Text))
{
inputHours = int.Parse(textBox1.Text);
}
// Minutes
if (!string.IsNullOrWhiteSpace(textBox2.Text))
{
inputMinutes = int.Parse(textBox2.Text);
}
// Seconds
if (!string.IsNullOrWhiteSpace(textBox3.Text))
{
inputSeconds = int.Parse(textBox3.Text);
}
// Updating richTextBox1 every second with remaining time left
totalSeconds = (inputHours * 3600) + (inputMinutes * 60) + inputSeconds;
timer1.Start();
while (ticks < totalSeconds)
{
TimeSpan time = TimeSpan.FromSeconds(totalSeconds);
string timeOutput = time.ToString(#"hh\:mm\:ss");
richTextBox1.AppendText(String.Format(timeOutput));
Thread.Sleep(1000);
richTextBox1.Clear();
}
// Shutting down computer
totalMilliseconds = ((inputHours * 3600) + (inputMinutes * 60) + inputSeconds) * 1000;
Thread.Sleep(totalMilliseconds);
richTextBox1.AppendText("end");
//Process.Start("shutdown", "/s /t 0");
}
private void timer1_Tick(object sender, EventArgs e)
{
ticks++;
}
}
}
As SLaks told, if you block the UI thread the box will never be updated, but in .net you have await/async, just convert your method to private async void button1_Click and instead of Thread.Sleep use await Task.Delay.
Also, you set the box content with
TimeSpan time = TimeSpan.FromSeconds(totalSeconds);
richTextBox1.AppendText(String.Format(timeOutput));
This should be
TimeSpan time = TimeSpan.FromSeconds(totalSeconds - ticks);
richTextBox1.AppendText(String.Format(timeOutput));
If you want a count-down.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Timers;
namespace ScrollLabelTest
{
class SaveOldHtml
{
private static int count;
private static Timer _timer = new Timer();
private static string page;
private static List<string> newText = new List<string>();
public SaveOldHtml(string DirectoryToSave,int count, string contents)
{
System.IO.File.WriteAllText(DirectoryToSave + "Page" + count.ToString("D6")
+ ".html", contents);
}
public SaveOldHtml(string DirectoryToSave, List<string> newTextList, int count)
{
using (StreamWriter myStream = new StreamWriter(DirectoryToSave + "newTextList" + count.ToString("D6")
+ ".txt"))
{
for (int i = 0; i < newTextList.Count; i++)
{
myStream.WriteLine(newTextList[i]);
}
}
}
public static void Start()
{
_timer.Elapsed += _timer_Elapsed;
_timer.Interval = 10000;
count = 5;
LoadOldHtmlFiles();
_timer.Start();
}
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
LoadOldHtmlFiles();
}
private static void LoadOldHtmlFiles()
{
page = File.ReadAllText(#"c:\temp\OldHtml\page" + count.ToString("D6") + ".html");
ListsExtractions.OffExtractions(#"c:\temp\OldHtml\page" + count.ToString("D6") + ".html", page, newText);
count ++;
}
}
}
The problem is that the first time in the Start method i call LoadoldHtmlfiles once and then after 10 seconds i call it again in the timer tick event.
But then next time it's not waiting another 10 seconds but jump right away to the timer tick event and call LoadoldhmtlFiles again.
And i checkec few times and searched all the solution i'm calling the method Start onlny once in form1 constructor.
If LoadOldHtmlFiles() takes >= 10 seconds then your timer will fire it repeatedly. Stop the timer and restart it in the _timer_Elapsed method:
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Stop();
LoadOldHtmlFiles();
_timer.Start();
}
If you place your main method inside timer tick function then your main method will be triggered after that timer is started, but to avoid this timer function being called again & again, stop this timer inside the timer tick function.
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
<your main function>
}
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;
}
}