Is it possible to do this class as a singelton? If so, how can I call the method onTick from the timer?
//Geir Otto
I tried running the latest code you sent, with the NEW in the constructor. It works fine for me - THE FIRST TIME in the sense that the instance property does return a value. But remember - the static constructor will only run once within a session. If for any reason the class gets garbage collected, it will never run again and the instance value will be gone. (Try it from the Procedure Editor for example, and run it twice. It will run the first time and not the 2nd.)
So I would say the doc is not exactly wrong, but it should probably be changed. You should have the NEW in the Get body of the instance property as your last post shows. Also, as I said before - remember that you must reset the Timer1:TickInterval from the TickInterval Set property or it will never change from its initial value.
And I don't think I'm qualified to explain why you would use the singleton model vs just using static properties for everything.
Sorry, it seems like my code was not added. Here it comes: Why would not this code run? What am I doing wrong when it comes to singelton?
This is the code that runs it:
def var oTimer as class JBoxTimer no-undo.
oTimer = JBoxTimer:Instance.
oTimer:TickInterval = 40.
The class fails to load..... why?
***********************************************************************
this is the class...
**********************************************************************
USING Progress.Lang.*.
BLOCK-LEVEL ON ERROR UNDO, THROW.
CLASS JBoxTimer:
define public static property instance as class JBoxTimer no-undo get. private set.
define public property TickInterval as int initial 60 no-undo get. set.
CONSTRUCTOR private JBoxTimer ():
end constructor.
constructor static JBoxTimer():
DEFINE VARIABLE components AS CLASS System.ComponentModel.Container NO-UNDO.
DEF VAR timer1 AS class System.Windows.Forms.Timer NO-UNDO.
components = NEW System.ComponentModel.Container().
timer1 = NEW System.Windows.Forms.Timer(components).
timer1:Interval = int(JBoxTimer:Instance:TickInterval) * 1000.
timer1:Enabled = TRUE.
Timer1:Tick:Subscribe(JBoxTimer:Instance:OnTick).
END CONSTRUCTOR.
/*------------------------------------------------------------------------------
Purpose:
Notes:
------------------------------------------------------------------------------*/
METHOD private VOID OnTick(input sender as System.Object, input e as System.EventArgs ):
/* DEFINE INPUT PARAMETER sender AS System.Object.*/
/* DEFINE INPUT PARAMETER e AS System.EventArgs.*/
MESSAGE 'OnTIck......'
VIEW-AS ALERT-BOX.
RETURN.
END METHOD.
METHOD private VOID Dummy(input iDummy as char):
RETURN.
END METHOD.
END CLASS.
As far as I can see you are never initializing the instance property. It's not enough to define it. You have to set it to an instance of the class. I.e, Normally you would add a code body for the Get and New an instance of the class:
Define public static property instance as JBoxTimer
Get:
Instance = new JBocTimer().
End.
I believe you can call the private constructor from a static property of the class.
However, in this case, I don't know why you even need an instance. Actually, when you access the Instance property , even though it returns ?, the static constructor will run. Then even if you created an instance, you are then setting the TickInterval and not doing anything with it. The code that used it has run already.
Maybe instead you want to set a static TickInterval property and move all that static constructor code into the property's Get body? You don't need a singleton. It would all just be static.
Laura, from the OpenEdge document:
documentation.progress.com/.../index.html
I have done it that way earlier, but I was told that you could do it in a differtent way, so I followed the documentation. I am not familiar with this way of coding, and to be honost, I am not sure what the diff is betveen static and singleton.
What I hoped to do, was to make ONE class that I could start and that would handle all my needs for a Timer. Till I fully understand this, I will drop the build of class and just use the code within each of the parts that needs a timer.
Ups, Laura, I see now that I have forgotten the most importen part of the code :-// I forgot the NEW part in start of the static constructor.... but still not working as hoped...
constructor static JBoxTimer():
JBoxTimer:instance = new JBoxTimer().
DEFINE VARIABLE components AS CLASS System.ComponentModel.Container NO-UNDO.
DEF VAR timer1 AS class System.Windows.Forms.Timer NO-UNDO.
components = NEW System.ComponentModel.Container().
timer1 = NEW System.Windows.Forms.Timer(components).
timer1:Interval = int(JBoxTimer:Instance:TickInterval) * 1000.
timer1:Enabled = TRUE.
Timer1:Tick:Subscribe(JBoxTimer:Instance:OnTick).
END CONSTRUCTOR.
By returning to this:
define public static property instance as class JBoxTimer no-undo
get():
if instance = ? then instance = new JBoxTimer().
return instance.
end get.
It seems to work.... Is the documentation wrong?
I tried running the latest code you sent, with the NEW in the constructor. It works fine for me - THE FIRST TIME in the sense that the instance property does return a value. But remember - the static constructor will only run once within a session. If for any reason the class gets garbage collected, it will never run again and the instance value will be gone. (Try it from the Procedure Editor for example, and run it twice. It will run the first time and not the 2nd.)
So I would say the doc is not exactly wrong, but it should probably be changed. You should have the NEW in the Get body of the instance property as your last post shows. Also, as I said before - remember that you must reset the Timer1:TickInterval from the TickInterval Set property or it will never change from its initial value.
And I don't think I'm qualified to explain why you would use the singleton model vs just using static properties for everything.
[quote user="Laura Stern"] And I don't think I'm qualified to explain why you would use the singleton model vs just using static properties for everything. [/quote] A couple observations -
I used statics a fair bit when I was first starting in OO, now I avoid them as much as possible. I might be able to justify a single static (ala SESSION) and hang dynamic instances off that static's properties - that would be about it.
And P.S: In the instance property code, I would not check for ?, I would use if VALID-OBJECT(...)
Define public static property instance as JBoxTimer
Get:
Instance = new JBocTimer().
End.
VS.
DEFINE PUBLIC STATIC PROPERTY Instance AS CLASS JBoxTimer NO-UNDO
GET.
PRIVATE SET.
with the Instance = new JBocTimer() in the constructor.
What is the point of using the second property if you can only use it once? And what would you do if you needed it in another part of the application? It seems like the first way of using property is the way I need to use it, since I want to call it several times, but just have it instansiated once....
The only problem I know have with the code, is that it will not fire the onTick event :-) it is not that easy to start using the new stuff :-) but fun!!
Sorry. You've lost me completely.
Obviously, you don't want to create a new instance EVERY time someone asks for one. You need to check if you have one already - as you showed earlier, but:
if NOT VALID-OBJECT(instance) then
instance = new JBoxTimer().
You said: " What is the point of using the second property". What property is that?
Of course the onTick even will not fire with the exact code you showed. The program is over before the time interval expires. You need to be in some kind of a I/O blocking - like a WAIT-FOR. With that, I do see the timer tick.
In my test I added a wait-for, but I will do a second check. Thanks :-)
The second property was the one that did not have the instance = new JBoxTimer() in the GET part.... That was taken from the documentation that I found for singeltons. I was trying it, but as you said, if I lost it, I could not call it more than once...
Still lost. You can call the instance property more than once. All I said was that the static constructor will only run once. Here's my code:
def var oTimer as class JBoxTimer no-undo.
oTimer = JBoxTimer:Instance.
oTimer:TickInterval = 6.
WAIT-FOR "CLOSE" OF THIS-PROCEDURE.
JBoxTimer.cls:
CLASS JBoxTimer:
DEFINE PRIVATE VAR timer1 AS class System.Windows.Forms.Timer NO-UNDO.
DEFINE PUBLIC STATIC PROPERTY Instance AS CLASS JBoxTimer NO-UNDO
GET:
IF NOT VALID-OBJECT(Instance) THEN DO:
Instance = NEW JBoxTimer( ).
Instance:InitializeTimer( ).
END.
RETURN Instance.
END.
PRIVATE SET.
DEFINE PUBLIC PROPERTY TickInterval AS INT INITIAL 3 NO-UNDO
GET.
SET (interv AS INT):
timer1:INTERVAL = interv * 1000.
END.
CONSTRUCTOR PRIVATE JBoxTimer( ):
/* Make the constructor private so it cannot be called from outside of
the class */
END CONSTRUCTOR.
METHOD PRIVATE VOID initializeTimer():
DEFINE VAR components AS CLASS System.ComponentModel.Container NO-UNDO.
components = NEW System.ComponentModel.Container().
timer1 = NEW System.Windows.Forms.Timer(components).
timer1:INTERVAL = TickInterval * 1000.
timer1:ENABLED = TRUE.
Timer1:Tick:Subscribe(OnTick).
END.
METHOD private VOID OnTick(input sender as System.Object, input e as System.EventArgs ):
MESSAGE 'OnTIck......' VIEW-AS ALERT-BOX.
END METHOD.
END.
Thanks Laura, now I understand more than when I started :-) It seems that I have been trying to do a mix of two things that does not mix that good. Also I didn't understand the use between static and singelton when looking at the example in the documentation. Anyway, this code you now gave me, did what I wanted, so I am happy :-) thanks a lot...