I create a subclass of Forms.Timer, and I cannot stop this timer.
public class Clock : Timer
{
private int startTime;
private PictureBox one;
private PictureBox two;
private PictureBox three;
public Clock(Size _size) : base()
{ startTime = 0; initialComponent(_size); }
public Clock(int start_time, Size _size) : base()
{ startTime = start_time; initialComponent(_size); }
public Point Location
{
get { return three.Location; }
set
{
three.Location = value;
two.Location = new Point(value.X + three.Width, value.Y);
one.Location = new Point(value.X + three.Width + two.Width, value.Y);
}
}
private void initialComponent(Size _size)
{
......
}
public void Show()
{
int bits = startTime % 10;
int ten = (startTime % 100) / 10;
int hundred = (startTime % 1000) / 100;
one.Image = ImageLauncher.loadImage(bits, ImageLauncher.ImageType.Timer);
two.Image = ImageLauncher.loadImage(ten, ImageLauncher.ImageType.Timer);
three.Image = ImageLauncher.loadImage(hundred, ImageLauncher.ImageType.Timer);
}
protected override void OnTick(EventArgs e)
{
startTime++;
if (startTime > 999 || startTime < 0) return;
this.Show();
}
}
I create an object in form's constructor, the timer can start normally, but the Stop() method doesn't work. I've tried to create a method to set Timer.Enabled to false, but it is still going, more weird is I tried to reset interval with timer.Enabled in a same method, the interval has changed but timer still has not disbaled.
In constructor:
clock = new Clock(new Size(23 * 3, 38));
start:
if (!clock.Enabled) clock.Start();
method with stop:
private void gameOver(bool is_win)
{
clock.Stop();
showAll();
string winface = is_win ? "cool" : "sad";
ShortCutStart.Image = ImageLauncher.loadImage(winface, ImageLauncher.ImageType.Face);
ShortCutStart.Name = winface;
}
Related
Please go through the following code which is an oversimplification of the code I have.
I need to know how once the timer is elapsed, how to return control to the main user control class, preferably to the same case within the switch statement.
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
//this is where I need to notify the main class that timer has expired and go to case 2
}
}
}
You can achieve the behavior that you want with events:
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public ucClass()
{
// Listen to event from timer
secObj.TimerExpired += (sender, args) =>
{
A = args.Count;
execute();
};
}
public void execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
public event EventHandler<TimerExpiredEventArgs> TimerExpired;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
// Send event with count
TimerExpired?.Invoke(this, new TimerExpiredEventArgs
{
Count = actualCount
});
}
}
}
public class TimerExpiredEventArgs
{
public int Count { get; set; }
}
I would recommend looking into the following;
The MVVM pattern
This will allow you to seperate the UI logic (passing around labels etc) and the control logic (timers etc).
Reactive Extensions (https://github.com/dotnet/reactive)
This would allow for a very simple timer:
Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(count => {
labelTimer.Text = count.ToString();
if (count > actualCount) {
A = args.Count;
execute();
}
});
I need to reverse DispatcherTimer
public TestTimer()
{
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0, 0, 1);
Timer.Tick += TimerTick;
StartTimer();
}
private DispatcherTimer Timer;
private int _seconds;
public int Seconds
{
get { return _seconds; }
set
{
if(value > -1 && value < 61)
_seconds = value;
}
}
private int _minutes;
public int Minutes
{
get { return _minutes; }
set
{
if (value > -1 && value < 61)
_minutes = value;
}
}
private int _hours;
public int Hours
{
get { return _hours; }
set
{
if (value > -1 && value < 25)
_hours = value;
}
}
public void StartTimer()
{
Timer.Start();
}
public void StopTimer()
{
Timer.Stop();
}
private void TimerTick(object sender, EventArgs e)
{
if (Seconds > 59)
{
Seconds = 0;
Minutes++;
if (Minutes > 59)
{
Minutes = 0;
Hours++;
if (Hours > 23)
Hours = 0;
}
}
Seconds++;
TimeFormat = string.Format("{0:00}:{1:00}:{2:00}",
Hours, Minutes, Seconds);
}
I'm not sure what you're trying to do or for what purpose.
If you want counting then you can use the TimerTick event handler to elapse every second and to count, or more efficiently, use DateTime.Now when you start, and subtract DateTime.Now when finished to get a TimeSpan between them.
If you're counting down, you can use the same approach but subtract the elapsed number of ticks away from your start to get your current countdown value.
I'm new OOP student, I wrote simple clock program on Xamarin studio with C#. The format of clock is 00:00:00. It should be count up and work as a clock.
However, there must be some problems thus my clock can be draw on screen but doesn't "tick".
using SwinGameSDK;
namespace MyGame
{
public class Clock
{
private Counter counter = new Counter();
private int _seconds;
private int _minutes;
private int _hours;
public Clock ()
{
_seconds = counter.SecondsCounter;
_minutes = counter.MinutesCounter;
_hours = counter.HoursCounter;
}
public int Seconds {
get {
return _seconds;
}
set {
_seconds = value;
}
}
public int Minutes {
get {
return _minutes;
}
set {
_minutes = value;
}
}
public int Hours {
get {
return _hours;
}
set {
_hours = value;
}
}
public void DrawClock ()
{
DrawHours ();
SwinGame.DrawText (":", Color.Black, "Arial", 80, 360, 200);
DrawMinutes ();
SwinGame.DrawText (":", Color.Black, "Arial", 80, 520, 200);
DrawSeconds ();
}
public void DrawHours ()
{
SwinGame.DrawText (Hours.ToString ("D2"), Color.Black, "Arial", 80, 250, 208);
}
public void DrawMinutes ()
{
SwinGame.DrawText (Minutes.ToString ("D2"), Color.Black, "Arial", 80, 410, 208);
}
public void DrawSeconds ()
{
SwinGame.DrawText (Seconds.ToString ("D2"), Color.Black, "Arial", 80, 560, 208);
}
public void UpdateClock ()
{
counter.UpdateCounter ();
}
public void ResetClock ()
{
counter.Reset ();
}
public void SetClock ()
{
counter.SetTimer ();
}
}
}
using System.Timers;
namespace MyGame
{
public class Counter
{
private int _hoursCounter;
private int _minutesCounter;
private int _secondsCounter;
public Counter ()
{
_hoursCounter = 0;
_minutesCounter = 0;
_secondsCounter = 0;
}
public int HoursCounter {
get {
return _hoursCounter;
}
set {
_hoursCounter = value;
}
}
public int MinutesCounter {
get {
return _minutesCounter;
}
set {
_minutesCounter = value;
}
}
public int SecondsCounter {
get {
return _secondsCounter;
}
set {
_secondsCounter = value;
}
}
Timer timer = new Timer ();
public void SetTimer ()
{
timer.Interval = 1000;
timer.Elapsed += (sender, e) => UpdateCounter ();
}
public void UpdateCounter ()
{
timer.Start ();
SecondsCounter += 1;
if (SecondsCounter == 60) {
SecondsCounter = 0;
MinutesCounter += 1;
}
if (MinutesCounter == 60) {
MinutesCounter = 0;
HoursCounter += 1;
}
if (HoursCounter == 24) {
HoursCounter = 0;
MinutesCounter = 0;
SecondsCounter = 0;
}
}
public void Reset ()
{
HoursCounter = 0;
MinutesCounter = 0;
SecondsCounter = 0;
timer.Close ();
}
}
}
using SwinGameSDK;
namespace MyGame
{
public class GameMain
{
public static void Main ()
{
var myClock = new Clock ();
//Open the game window
SwinGame.OpenGraphicsWindow ("GameMain", 800, 600);
SwinGame.ShowSwinGameSplashScreen ();
//Run the game loop
while (false == SwinGame.WindowCloseRequested ()) {
//Fetch the next batch of UI interaction
SwinGame.ProcessEvents ();
//Clear the screen and draw the framerate
SwinGame.ClearScreen (Color.White);
SwinGame.DrawFramerate (0, 0);
myClock.DrawClock ();
myClock.SetClock ();
if (SwinGame.MouseClicked (MouseButton.LeftButton)) {
myClock.UpdateClock ();
}
if (SwinGame.MouseClicked (MouseButton.RightButton)) {
myClock.ResetClock ();
}
//Draw onto the screen
SwinGame.RefreshScreen (60);
}
}
}
}
The reason your clock is not ticking because you are continuously resetting it's interval using myClock.SetClock() method. This method should be only called only once outside the while loop in main method. Try following main method;
public static void Main ()
{
var myClock = new Clock ();
//Open the game window
SwinGame.OpenGraphicsWindow ("GameMain", 800, 600);
SwinGame.ShowSwinGameSplashScreen ();
myClock.SetClock (); //Set clock should be called from here.
//Run the game loop
while (false == SwinGame.WindowCloseRequested ()) {
//Fetch the next batch of UI interaction
SwinGame.ProcessEvents ();
//Clear the screen and draw the framerate
SwinGame.ClearScreen (Color.White);
SwinGame.DrawFramerate (0, 0);
myClock.DrawClock ();
if (SwinGame.MouseClicked (MouseButton.LeftButton)) {
myClock.UpdateClock ();
}
if (SwinGame.MouseClicked (MouseButton.RightButton)) {
myClock.ResetClock ();
}
//Draw onto the screen
SwinGame.RefreshScreen (60);
}
}
And SetTimer should be as follows
public void SetTimer ()
{
timer.Interval = 1000;
timer.Elapsed += (sender, e) => UpdateCounter ();
timer.Start ();
}
It seems like you dont even start the timer.
instead of calling timer.Start (); in UpdateCounter (), start the timer after timer.Elapsed += (sender, e) => UpdateCounter ();.
you should also keep your variables together.
private int _hoursCounter;
private int _minutesCounter;
private int _secondsCounter;
Timer timer;
and initialize the timer in the constructor:
..
_secondsCounter = 0;
timer = new Timer();
This is the code in Form1:
private void Form1_MouseWheel(object sender, MouseEventArgs e)
{
PbsWheel pbsw = new PbsWheel(pbs, pb, e.Delta, pb.AnimateRate, label2);
}
In the bottom of form1 i have this class:
public class AnimatedPictureBox : PictureBox
{
List<string> imageFilenames;
Timer t = new Timer();
public AnimatedPictureBox()
{
AnimateRate = 100; //It's up to you, the smaller, the faster.
t.Tick += Tick_Animate;
}
public int AnimateRate
{
get { return t.Interval; }
set { t.Interval = value; }
}
public void Animate(List<string> imageFilenames)
{
this.imageFilenames = imageFilenames;
t.Start();
}
public void StopAnimate()
{
t.Stop();
i = 0;
}
int i;
private void Tick_Animate(object sender, EventArgs e)
{
if (imageFilenames == null) return;
Load(imageFilenames[i]);
i = (i + 1) % imageFilenames.Count;
}
}
Now in the new class i have the same class AnimatedPcitureBox and also this code:
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WeatherMaps
{
class PbsWheel
{
public PbsWheel(AnimatedPictureBox[] pbs, AnimatedPictureBox pb, int delta, int speed,Label label2)
{
//if (leave == true)
//{
for (int i = 0; i < pbs.Length; i++)
{
if (delta > 0)
{
if (speed < 5000)
{
if (speed < 1000)
{
speed += 100;
label2.Text = (speed / (double)1000).ToString();
}
else
{
speed += 1000;
label2.Text = (speed / 1000).ToString();
}
}
}
else
{
if (speed > 1000)
{
speed -= 1000;
label2.Text = (speed / 1000).ToString();
}
else
if (speed <= 1000 && speed > 100)
{
speed -= 100;
label2.Text = (speed / (double)1000).ToString();
}
}
}
//}
}
public class AnimatedPictureBox : PictureBox
{
List<string> imageFilenames;
Timer t = new Timer();
public AnimatedPictureBox()
{
AnimateRate = 100; //It's up to you, the smaller, the faster.
t.Tick += Tick_Animate;
}
public int AnimateRate
{
get { return t.Interval; }
set { t.Interval = value; }
}
public void Animate(List<string> imageFilenames)
{
this.imageFilenames = imageFilenames;
t.Start();
}
public void StopAnimate()
{
t.Stop();
i = 0;
}
int i;
private void Tick_Animate(object sender, EventArgs e)
{
if (imageFilenames == null) return;
Load(imageFilenames[i]);
i = (i + 1) % imageFilenames.Count;
}
}
}
}
But when im doing in Form1 this line:
PbsWheel pbsw = new PbsWheel(pbs, pb, e.Delta, pb.AnimateRate, label2);
Im getting 3 errors on pbs and pb. And pbs and pb are AnimatedPictureBox type.
Error 11 Argument 1: cannot convert from 'WeatherMaps.Form1.AnimatedPictureBox[]' to 'WeatherMaps.PbsWheel.AnimatedPictureBox[]'
Error 12 Argument 2: cannot convert from 'WeatherMaps.Form1.AnimatedPictureBox' to 'WeatherMaps.PbsWheel.AnimatedPictureBox'
Error 10 The best overloaded method match for 'WeatherMaps.PbsWheel.PbsWheel(WeatherMaps.PbsWheel.AnimatedPictureBox[], WeatherMaps.PbsWheel.AnimatedPictureBox, int, int, System.Windows.Forms.Label)' has some invalid arguments
You actually have 2 separate classes for AnimatedPictureBox as you have them as internal classes inside Form1 and WeatherMaps. It doesn't matter that the code and name is the same - the classes are different.
It will be better for you to move it to a new class that is not sitting inside any other class. Preferably you can move it to its own file too.
well the error is clear.
there are two classes with the same name in different namespaces.
create a new file an put it there, use it in both form / PbsWeel
Another way on doing it is to create a custom control. By adding the custom control to your Form1, the Form1.Designer will do the things for you.
I am trying to create an event that executes a function when a certain amount of time has changed. The timer is done by another code, it's supposed to call Plus(1), but will that change all timers (if I create multiple)? And this code is not actually working.
namespace #event
{
class Program
{
static void Main(string[] args)
{
Tick tijd = new Tick();
tijd.interval = 10;
tijd.TijdVeranderd += new EventHandler(Uitvoeren);
dynamic func = new Tick();
for (int i = 0; i < 100; i++)
{
func.Plus(1);
}
Console.ReadLine();
}
static void Uitvoeren(object sender, EventArgs e)
{
Console.WriteLine("Uitgevoerd!");
}
}
public class Tick
{
public event EventHandler TijdVeranderd;
public int interval;
private int tijd;
public void Plus(int i)
{
tijd += 1;
}
public int Verander
{
get { return this.tijd; }
set
{
this.tijd = value;
if (tijd == interval)
{
if (this.TijdVeranderd != null)
this.TijdVeranderd(this, new EventArgs());
tijd = 0;
}
}
}
public Tick() { }
}
}
EDIT: I don't want to use the .net timer, I want to create my own.
Just use .net timer like this:
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
aTimer.Interval = 1000; //here you can set your interval
aTimer.Start();
Here you can catch the event and call other method:
void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//TODO: call your method like "Plus"
}
There seem to be a couple of errors in your code:
First of all, in Main, you are calling Plus() on a different instance of Tick than the one that you configured. Try using tijd.Plus(1) instead of func.Plus(1).
Also, in the implementation of Plus, when you increment the private variable tijd, the code associated with the property Verander does not get executed, so no events ever fire. To quickly fix, increment Verander instead of tijd.
namespace #event
{
class Program
{
static void Main(string[] args)
{
Tick tijd = new Tick();
tijd.interval = 10;
tijd.TijdVeranderd += new EventHandler(Uitvoeren);
for (int i = 0; i < 100; i++)
{
tijd.Plus(1);
}
Console.ReadLine();
}
static void Uitvoeren(object sender, EventArgs e)
{
Console.WriteLine("Uitgevoerd!");
}
}
public class Tick
{
public event EventHandler TijdVeranderd;
public int interval;
private int tijd;
public void Plus(int i)
{
Verander += 1;
}
public int Verander
{
get { return this.tijd; }
set
{
this.tijd = value;
if (tijd == interval)
{
if (this.TijdVeranderd != null)
this.TijdVeranderd(this, new EventArgs());
tijd = 0;
}
}
}
public Tick() { }
}
}
You can try with this code
private static System.Timers.Timer aTimer;
public static void Main()
{
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
I don't know why you wouldn't use a system timer, but here's an [untested] implementation of a timer that should do the trick:
class MyCrudeTimer : IDisposable
{
public event EventHandler Alarm ;
public TimeSpan Duration { get ; private set ; }
public bool AutomaticallyReset { get ; private set ; }
public bool IsRunning { get ; private set ; }
private Thread timerThread ;
private ManualResetEvent start ;
private void TimerCore()
{
try
{
while ( start.WaitOne() )
{
System.Threading.Thread.Sleep( Duration ) ;
Alarm( this , new EventArgs() ) ;
}
}
catch ( ThreadAbortException )
{
}
catch ( ThreadInterruptedException )
{
}
return ;
}
public MyCrudeTimer( TimeSpan duration , bool autoReset )
{
if ( duration <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("duration must be positive","duration") ;
this.Duration = duration ;
this.AutomaticallyReset = autoReset ;
this.start = new ManualResetEvent(false) ;
this.timerThread = new Thread( TimerCore ) ;
this.timerThread.Start() ;
return ;
}
public void Start()
{
if ( IsRunning ) throw new InvalidOperationException() ;
IsRunning = true ;
start.Set() ;
return ;
}
public void Stop()
{
if ( !IsRunning ) throw new InvalidOperationException() ;
IsRunning = false ;
start.Reset() ;
return ;
}
public void Dispose()
{
try
{
if ( this.timerThread != null )
{
this.timerThread.Abort() ;
this.timerThread = null ;
}
}
catch
{
}
return ;
}
}