I am trying get setup a Recording Time label so that when a user clicks a button it starts and when they click another button it stops.
I have tried two different things which have not worked.
Setting a Ticker and increment a value by 1 and displaying it.
This did not work as i am also doing other things in the ticker which means it might take 1.5 seconds but i'm increment by 1, therefore the longer the recording goes on the more inaccruate it is.
Getting the TimeOfDay when the stream starts and on the ticker method getting the TimeOfDay and subtracting them.
This is not working because if the recording is left overnight the time turns into minuses I.E -67647.74 seconds.
private void StreamClick_Click(object obj)
{
_streamStartTime = DateTime.Now.TimeOfDay;
}
private void LiveVideoStream_Tick(VideoCaptureDevice cam)
{
_currentRecordTime = DateTime.Now.TimeOfDay - _streamStartTime;
RecordTime = _currentRecordTime.ToString();
}
Does anyone have any other ideas how I can display a nice timer.
Your _streamStartTime should be a DateTime too. Then in your Click event handler, assign DateTime.Now to it, don't use TimeOfDay only:
private void StreamClick_Click(object obj)
{
_streamStartTime = DateTime.Now;
}
Then in your calculation, you simply need to negate the two DateTime to get TimeSpan. Use the TimeSpan to produce your time string:
private void LiveVideoStream_Tick(VideoCaptureDevice cam)
{
TimeSpan _currentRecordTime = DateTime.Now - _streamStartTime;
string RecordTime = _currentRecordTime.TotalDays.ToString() + " " + _currentRecordTime.Hours.ToString() + ":" +
_currentRecordTime.Minutes.ToString() + ":" + _currentRecordTime.Seconds.ToString();
}
Do not use DateTime.Now because the system clock can jump backwards or forwards on rare occasions. DateTime.UtcNow is a lot safer - no daylight saving - but still not bulletproof.
You should use StopWatch instead.
Related
I'm making autoclicker program and I already have an issue. I want my program to be able to change the clicks per second field just how the user wants it. So I made this.
private void textBoxCps_TextChanged(object sender, EventArgs e)
{
try
{
time = Convert.ToDouble(textBoxCps.Text);
time = 1000 / time;
Math.Round(time);
}
catch (Exception)
{
}
}
The math is right(I think...)
while (IsRunning)
{
if ((Control.ModifierKeys & Keys.Alt) != 0)
{
DoMouseClicks();
Thread.Sleep(Convert.ToInt32(time));
}
else
{
}
}
When I try to put 1 CPS into the textbox it does 1 click per second, the same for 2 and 3 but when it's 4 and higher I'm getting 3.80 and lower CPS.
So the operator types some text that should represent a period of time (TimeSpan), and after running is started, you want to call method DoMouseClicks every TimeSpan, until running is stopped.
One of the problems is, that while you are doing this procedure you want your user input to be responsive.
Instead of Sleep, you should use one of the windows timers. There are several of them, and each have their advantages and disadvantages. In your case, the timer that you use depends on the accuracy that you need. See this article for a comparison between the various timers
Is it a problem if the clicks are a bit delayed if the user thread is busy? If not, the easiest is a System.Timers.Timer
System.Timers.Timer timer = new System.Timers.Timer()
timer.Elapsed += TimerElapsed;
private void TimerElapsed(object sender, ...)
{
DoMouseClicks();
}
To change the interval:
TimeSpan TimerInterval
{
get => TimeSpan.FromMilliseconds(this.timer.Interval);
set => this.Timer.Interval = value.TotalMilliseconds;
}
I decided to use a TimeSpan as interval time. This way you code changes are minimal if in future versions you decide to let the operator type his interval times in seconds, or in time format ("01:00")
To start and stop the timer:
private bool IsTimerStarted
{
get => this.timer.Enable;
set => this.timer.Enabled = value;
}
Now we are ready to react on operator input. You decided to act on TextBoxChanged. Are you sure you want this? What happens if an operator wants to type "1000", to indicate one second time interval. He starts by typing "1", you immediately start the mouse clicks with a frequency of 1 msec. Is this what you want?
Another problem: if the operator makes a typing error: "10)0", instead of "1000"?
A proper user interface would let the operator indicate that he finished typing the interval by pressing a button. When the button is pressed you read the text. If there is an error, you notify the operator, if not, you start the timer.
An alternative is to disable the button as long as the text box contains invalid text. Although this seems nice, the disadvantage is that the operator does not know why his button is not enabled.
private void OnButtonStart_Clicked(object sender, ...)
{
TimeSpan intervalTime = this.ReadTextBoxInterval();
this.TimerInterval = intervalTime;
this.IsTimerStarted = true;
// if desired: show the operator that the action is running
}
private void OnButtonStop_Clicked(object sender, ...)
{
this.IsTimerStarted = false;
// if the timer was handling event Elapsed, it is finished neatly.
// if desired show the operator that the action is stopped.
}
I decided to separate the action from the interpretation of the operator input. This way, code changes are minimal if you decide to change the operator input from msec to seconds, or even time format ("00:01"). Or if you decide to use a ComboBox instead of an edit box.
TimeSpan ReadTextBoxInterval()
{
string textBoxText = this.TextBoxInterval.Text;
return IntervalFromMsecText(textBoxText);
}
TimeSpan IntervalFromMsecText(string intervalText)
{
if (Double.TryParse(intervalText, NumberStyles.Any, CultureInfo.CurrentCulture,
out double msecInterval))
{
// input is a proper double
return TimeSpan.FromMilliseconds(msecInterval);
}
else
{
// invalid input. Notify the operator?
}
}
I had a task to make reflex meter app, and I got and exe as an example. I made it work but I don't get the same results from example I was given and my app, it's like I have 60-70 ms lost somewhere. App is supposed to show a text at random time between 0.5 and 5 seconds and when text shows, the user is supposed to click a button that will stop the stopwatch class I was using here and write it into last and best times.
First I was saving TotalMilliseconds , seconds , milliseconds and minutes as double , and now as TimeSpan, I felt as when I saved it in TimeSpan it reduced time but not enough to be close as example app or even online reflex app. I was thinking about delay between events or even mouse click, but I don't think its supposed to be like 50 60 ms. And if that is the problem how to measure those.
These are start events
private void Start_B_Click(object sender, EventArgs e)
{
Random rnd = new Random();
RndTimer.Interval = rnd.Next(500, 5000);
RndTimer.Start();
}
Stopwatch s = new Stopwatch();
private void RndTimer_Tick(object sender, EventArgs e)
{
NOW_L.Visible = true;
s.Reset();
s.Start();
Random rnd = new Random();
RndTimer.Interval = rnd.Next(500, 5000);
}
and this is button click event
public double o;
private void Click_B_Click(object sender, EventArgs e)
{
if (NOW_L.Visible == true)
{
s.Stop();
TimeSpan ts = s.Elapsed;
NOW_L.Visible = false;
if (LtimeRez_LB.Text == "00:00:00" || ts.TotalMilliseconds < class1.m)
{
LtimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
BesttimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
class1.m = ts.TotalMilliseconds;
o = class1.m;
}
else if (ts.TotalMilliseconds > o || ts.TotalMilliseconds == o)
{
LtimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
}
NOW_L.Visible = false;
}
}
LtimeRez variable is label that is displaying last result and BestTimeRez is best time result, also I used public static double variable called m
Use the MouseDown event of the Button instead of the Click event. The Click event will only be triggered some time later than when the user pressed the mouse button on the control because it first waits for the user to also release the mouse button and because it also has to perform some internal tasks first (redrawing the button, validation checks).
Additional notes on the code:
Don't create a new instance of the Random class each time. Create one instance once and reuse it all the time. See How do I generate a random int number in C#?
In the Timer Tick function, only start the Stopwatch after setting the timer interval. The button will actually only become visible when the code leaves that function and has a chance again to process Windows messages.
Please give o and m some meaningful names. You don't need both variables. They always have the same value. You only need one of them.
In CLick_B_Click, you don't need the if in the else part.
In the current version of the code, when the user does not click immediately, the timer click event can happen multiple times before the user clicks the button, resetting the stopwatch too early...
One problem I am seeing here is string concatenation in you code. In C# world, while concatenating you should use String.Format() method. Using plus operator to join the string will add delay. So use below line to form string -
LtimeRez_LB.Text = String.Format("{0}:{1}:{2}", ts.Minutes, ts.Seconds, ts.Milliseconds);
~Nilesh
I'm currently working with a Bluetooth module, for which my application automatically scans in order auto-connect.
What i'm trying to achieve though, is to implement a restriction in terms of the amount of time that the application is allowed to scan for the module. I figured that it made good sense to use system.threading.Timer for this purpose, to run behind code.
if(c = 1)
{
bleText.Text = "Scanning...";
Scan_Function();
}
Private void Scan_Function()
{
//Timer stuff
}
However, i'm unaware if this is the correct way of doing it, and how i might be done.
You don't need a timer, just get the time when task starts and subtract it from the time it ends:
Private void Scan_Function()
{
DateTime start = DateTime.Now;
//Timer stuff
double milliSecondsElapsed = (DateTime.Now - start).TotalMilliSeconds;
}
Of course you can use these 2 lines outside the method too:
DateTime start = DateTime.Now;
Scan_Function()
double milliSecondsElapsed = (DateTime.Now - start).TotalMilliSeconds;
Just can't get it with datepicker validation.
I have datepicker From and datepicker To, so I want to prevent the user from doing some kung fu and seting datepicker From to be bigger than datepicker To, I've bumped across some questions but couldn't find the answer, so I've tried doing the easiest way I could think of:
Set MaxDate property for datepicker from in form_load event
private void Form1_Load(object sender, EventArgs e)
{
datepickerFrom.MaxDate = datepickerFrom.Value;
}
Then do the same for value_changed event
private void datepickerFrom_ValueChanged(object sender, EventArgs e)
{
datepickerFrom.MaxDate = datepickerFrom.Value;
}
This was easy and fine, only few lines of code, and I've only needed datepickerFrom_ValueChanged event, but recently I've tried typing date into datepicker insted of selecting it, and then all hell broke loose.
So I came to some solution for validation, instead of setting MaxDate property, I've tried this.
private void dtFrom_ValueChanged(object sender, EventArgs e)
{
DateTime from = datepickerFrom.Value;
DateTime to = datepickerTo.Value;
int year= from.Year > to.Year ? to.Year : from.Year;
int month = from.Month > to.Month ? to.Month : from.Month;
int day = from.Day > to.Day ? to.Day : from.Day;
int hour = from.Hour > to.Hour ? to.Hour : from.Hour;
int minute = from.Minute > to.Minute ? to.Minute : from.Minute;
int second = from.Second > to.Second ? to.Second : from.Second;
//setting datepicker value
datepickerFrom.Value = new DateTime(year, month, day, hour, minute, second);
}
This works fine, but feels like bit of headache, and I have to do this for datepickerTO_ValueChanged event also, sure I could make one method and call it two times, but still feels like there is a batter way for this, so any suggestions?
Thank you for your time
Solution 1:
You can handle datePickerTo close event and do something like:
private void dateTimePickerTo_CloseUp(object sender, EventArgs e)
{
DateTime fromdate = Convert.ToDateTime(dateTimePickerFrom.Value);
DateTime todate1 = Convert.ToDateTime(dateTimePickerTo.Value);
if (fromdate > todate1)
//Error
}
You can also use DateTime.Compare whcih get two date
like
int result = DateTime.Compar(dateTimePickerFrom.Value ,dateTimePickerTo.Value);
if result is 1 means From date is earlier, see this link.
Note1:
but as you said if user type in From or To textboxes then closeup event never fire so you need compare them in where you want to process
such as button click.
Note2:
As #Sinatr comment if Value is DateTime then don't need to convert it so the code would be like:
if (dateTimePickerFrom.Value >dateTimePickerTo.Value)
//Error
Your proposal would lead to a horrible interface. Suppose the following case:
From = 1 jan 2000
To = 1 feb 2000
User wants to change both values to 2010. He starts with the from value:
From = 1 jan 2010
Now he wants to change the TO value to 1 feb 2010. Alas, he can't.
Proper usage would be: add some button with which the operator can affirm he has changed all data, start checking it and update. In windows this button is usually named Apply Now or OK. Why deviate from this windows standard.
private void OnFormLoading(object sender, ...)
{
this.FromDate.MinValue = ... // use the real absolute min value you want ever to allow
this.FromDate.MaxValue = ...;
this.ToDate.MinValue = ...;
this.ToDate.MaxValue = ...;
}
Don't do any checking as long as the operator is making changes. Strat checking the input values when he indicates that he finished making changes:
private void OnButtonApplyNow_Clicked(object sender, ...)
{
bool InputOk = CheckInput();
if (!inputOk)
{
ShowIncorrectInput(); // for instance using a MessageBox
}
}
I am storing Datetime in a session as mentioned below:-
Session["LoggedInTime"] = System.DateTime.Now;
Then i m retrieving this value on a page load like this:-
DateTime _loggedInTime = Convert.ToDateTime(Session["LoggedInTime"]);
I debug the above code code and find that up to here the _loggedInTIme is showing the correct date which i m storing in it. After that i m calculating the time span like this:-
TimeSpan elapsedtimespan = System.DateTime.Now.Subtract(_loggedInTime);
int elapsedtime = Convert.ToInt32(elapsedtimespan.TotalSeconds);
I found while debugging the code that ,while subtraction the _loggedInTime = {1/1/0001 12:00:00 AM} and due to which i m not able to get exact elapsedtime .
Please help me to solve this issue as i m not getting why the _loggedInTime become {1/1/0001 12:00:00 AM} at calculating TimeSpan.
The following works fine for me. Since you prefix _loggedInTime with an underscore I'm assuming you declared it as an instance variable of the page itself.
private DateTime _loggedInTime;
protected void Page_Load(object sender, EventArgs e)
{
if (Session["LoggedInTime"] == null)
Session["LoggedInTime"] = DateTime.Now;
_loggedInTime = Convert.ToDateTime(Session["LoggedInTime"]);
TimeSpan elapsedtimespan = DateTime.Now.Subtract(_loggedInTime);
int elapsedtime = Convert.ToInt32(elapsedtimespan.TotalSeconds);
}
I'm guessing that you are calculating the elapsed time at another time and not in the Page_Load as in the above example.
Make sure that on each post back you correctly load the elapsed time from the session before calculating the elapsed time. On the next post back the _loggedInTime is reset to the default value of a DateTime, being {1/1/0001 12:00:00 AM}.
I think you have something to the following setup.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["LoggedInTime"] == null)
Session["LoggedInTime"] = DateTime.Now;
_loggedInTime = Convert.ToDateTime(Session["LoggedInTime"]);
}
}
private void ButtonClick(object sender, ImageClickEventArgs e)
{
TimeSpan elapsedtimespan = DateTime.Now.Subtract(_loggedInTime);
int elapsedtime = Convert.ToInt32(elapsedtimespan.TotalSeconds);
}
Here I demonstrate it by handling a postback when a button is clicked. In that case the Page_Load does not load the LoggedInTime and the elapsed time is calculated incorrectly. To solve this, just remove the IsPostBack if statement in the Page_Load. Make sure you set the instance variable _loggedInTime each time you load the page, thus also on a postback.
Remark: Also check if you are on a server farm. If you are using multiple servers to handle your requests but have configured the wrong session mode (e.g. in process) then server A will store the session variable in its memory, but the redirect can be handled by server B, which doesn't know about server A's in-memory session store.
More information can be found on MSDN:
Session-State Modes
In process session state is the default, in a server farm scenario you can use the StateServer or SqlServer alternatives to share session state between the servers. Or you can write your own custom session state provider.
Since that's the default value for DateTime, I'm guessing you're attempting to use loggedInTime when it was not previously initialized in the Session object. In other words, my suggestion is to try something along these lines:
int elapsedtime = 0;
if (Session["LoggedInTime"] != null)
{
DateTime _loggedInTime = (DateTime)Session["LoggedInTime"];
TimeSpan elapsedtimespan = System.DateTime.Now.Subtract(_loggedInTime);
elapsedtime = Convert.ToInt32(elapsedtimespan.TotalSeconds);
}
else Session["LoggedInTime"] = System.DateTime.Now;