Callback For A Timer Event To Display Widget in Ruby/Tk

Kind All,

Um, I need to code an elapsed time display in Ruby/Tk.

It was straightforward to use the Time class and the Time#srtftime
method to get the time in just the form I wanted: t = Time.new; puts
“Time is #{t.strftime(”%I:%M:%S %p")}"

Likewise, for displaying the string in a TkLabel widget:
TkLabel.new(canvas, ‘text’=>“The time is #{t.strftime(”%I:%M:%S %p")}"
).pack( ‘side’=>‘top’, ‘padx’=>15, ‘pady’=>15 )

It was also easy to understand binding in general: root.bind(‘q’) { exit
}.

Or to setup a callback for a TkButton press: myButton =
TkButton.new(root, ‘text’=>‘Click me!’, ‘command’=> proc { btnProc()
}).place( ‘x’=>x, ‘y’=>y, ‘width’=>w, ‘height’=>h )

But, I have searched high and low, and I can not find out how to set up
a callback for a timer event. I just want to display a time string on
the TkCanvas or TkTopLevel window once per second. I have gone through
a Perl/Tk reference book and I’m still having trouble figuring out how
to “translate” this into Ruby/Tk.

I’ll of course keep searching and trying stuff, but if anyone
knowledgeable has a code example of how to this, or can point me to one,
or point me to a reference to the technique, I’d be grateful. Thank you
and best regards,

David

From: David B. [email protected]
Subject: Callback For A Timer Event To Display Widget in Ruby/Tk
Date: Mon, 27 Mar 2006 23:14:23 +0900
Message-ID: [email protected]

But, I have searched high and low, and I can not find out how to set up
a callback for a timer event. I just want to display a time string on
the TkCanvas or TkTopLevel window once per second. I have gone through
a Perl/Tk reference book and I’m still having trouble figuring out how
to “translate” this into Ruby/Tk.

For such case which is sensitive about interval time,
I recommend TkRTTimer class ( available Ruby 1.8.3 or later).
That is unique to Ruby/Tk.
Please see “/ext/tk/sample/tkrttimer.rb”.
It shows the difference between TkTimer class and TkRTTimer class.

TkTimer :: TkTimer.new(inerval, -1, operation).start

| operation | | operation | | operation |
–±----------±-----------±----------±-----------±----------±->
time-line
| interval | | interval |

TkRTTimer :: TkRTTimer.new(inerval, -1, operation).start

| operation | | operation | | operation |
–±----------±--------±----------±--------±----------±------->
time-line
| interval | interval | interval

argument ‘-1’ means infinite loop

===========================================================================

Hidetoshi NAGAI wrote:

From: David B. [email protected]
Subject: Callback For A Timer Event To Display Widget in Ruby/Tk
Date: Mon, 27 Mar 2006 23:14:23 +0900
Message-ID: [email protected]

But, I have searched high and low, and I can not find out how to set up
a callback for a timer event. I just want to display a time string on
the TkCanvas or TkTopLevel window once per second. I have gone through
a Perl/Tk reference book and I’m still having trouble figuring out how
to “translate” this into Ruby/Tk.

For such case which is sensitive about interval time,
I recommend TkRTTimer class ( available Ruby 1.8.3 or later).
That is unique to Ruby/Tk.
Please see “/ext/tk/sample/tkrttimer.rb”.
It shows the difference between TkTimer class and TkRTTimer class.

TkTimer :: TkTimer.new(inerval, -1, operation).start

| operation | | operation | | operation |
–±----------±-----------±----------±-----------±----------±->
time-line
| interval | | interval |

TkRTTimer :: TkRTTimer.new(inerval, -1, operation).start

| operation | | operation | | operation |
–±----------±--------±----------±--------±----------±------->
time-line
| interval | interval | interval

argument ‘-1’ means infinite loop

===========================================================================

Kind Responder,

Thank you very much. I am forever grateful.

David

Hidetoshi NAGAI wrote:

From: David B. [email protected]
Subject: Callback For A Timer Event To Display Widget in Ruby/Tk
Date: Mon, 27 Mar 2006 23:14:23 +0900
Message-ID: [email protected]

But, I have searched high and low, and I can not find out how to set up
a callback for a timer event. I just want to display a time string on
the TkCanvas or TkTopLevel window once per second. I have gone through
a Perl/Tk reference book and I’m still having trouble figuring out how
to “translate” this into Ruby/Tk.

For such case which is sensitive about interval time,
I recommend TkRTTimer class ( available Ruby 1.8.3 or later).
That is unique to Ruby/Tk.
Please see “/ext/tk/sample/tkrttimer.rb”.
It shows the difference between TkTimer class and TkRTTimer class.

Hidetoshi,

I have coded the ‘elapsed time’ display that I needed. I used TkTimer
versus TkRTTimer because I am at 1.8.2 currently, and I do not require
accurate real-time event handling at this time. If and when I do, I
will use the TkRTTimer class.

I have two quick questions: will my creation of all those Time.new
objects (two per second) cause me to run out of resources if I do it for
a long time?

Secondly, while this ‘elapsed time’ code works:

“Elapsed is #{(Time.at(Time.new.to_i - (oldTime.to_i -
18000))).strftime(”%X")}"

I have a sneaky feeling that it is not the best (Ruby?) way. Is it way
too resource wasteful, and if so, is there a more “Ruby” way?

In any case, I thank you for your help,

David

P.S. It took me a while to translate “/ext/tk/sample/tkrttimer.rb” into the URL where the code actually
was. But I figured you meant that to be a test of my ‘worthiness’!
(:>)

P.P.S. The test that I constructed, straight from your example, follows:

continuously display ‘current’ and ‘elapsed’ time once per second


require ‘tk’

root = TkRoot.new(:title=>‘Timer Event Example’)

label2 = TkLabel.new(:parent=>root, :width=>10)
.pack(:side=>:bottom, :fill=>:both)

label = TkLabel.new(:parent=>root, :width=>10)
.pack(:side=>:bottom, :fill=>:both)

oldTime = Time.new

define the ‘current time’ procedure repeated by the TkTimer object

timeProc = proc{|tObj| #<== TkTimer object
tRtnVal = tObj.return_value + 1000 # return_value keeps a result of
the last proc
label.text format(“Time is #{Time.new.strftime(”%X")}",
*(cnt.divmod(100)))
tRtnVal
}

define the ‘elapsed time’ procedure repeated by the TkTimer object

elapsedProc = proc{|tObj2| #<== TkTimer object
tRtnVal2 = tObj2.return_value + 1000 # return_value keeps a result of
the last proc
label2.text format(“Elapsed is #{(Time.at(Time.new.to_i -
(oldTime.to_i - 18000))).strftime(”%X")}", *(cnt.divmod(100)))
tRtnVal2
}

timer = TkTimer.new(1000, -1, timeProc).start(0, proc{ label.text(‘The
time is …’); 0 })

timer2 = TkTimer.new(1000, -1, elapsedProc).start(0, proc{
label2.text(‘Elapsed time is …’); 0 })

ev_quit = TkVirtualEvent.new(‘Control-c’, ‘Control-q’, ‘q’)

Tk.root.bind(ev_quit, proc{Tk.exit}).focus

Tk.mainloop

Hidetoshi NAGAI wrote:

Hidetoshi,

I have coded the ‘elapsed time’ display that I needed. I used TkTimer
versus TkRTTimer because I am at 1.8.2 currently, and I do not require
accurate real-time event handling at this time. If and when I do, I
will use the TkRTTimer class.

I have two quick questions: will my creation of all those Time.new
objects (two per second) cause me to run out of resources if I do it for
a long time?

Secondly, while this ‘elapsed time’ code works:

“Elapsed is #{(Time.at(Time.new.to_i - (oldTime.to_i -
18000))).strftime(”%X")}"

I have a sneaky feeling that it is not the best (Ruby?) way. Is it way
too resource wasteful, and if so, is there a more “Ruby” way?

In any case, I thank you for your help,

David

P.S. It took me a while to translate “/ext/tk/sample/tkrttimer.rb” into the URL where the code actually
was. But I figured you meant that to be a test of my ‘worthiness’!
(:>)

P.P.S. The test that I constructed, straight from your example, follows:

continuously display ‘current’ and ‘elapsed’ time once per second


require ‘tk’

root = TkRoot.new(:title=>‘Timer Event Example’)

label2 = TkLabel.new(:parent=>root, :width=>10)
.pack(:side=>:bottom, :fill=>:both)

label = TkLabel.new(:parent=>root, :width=>10)
.pack(:side=>:bottom, :fill=>:both)

oldTime = Time.new

define the ‘current time’ procedure repeated by the TkTimer object

timeProc = proc{|tObj| #<== TkTimer object
tRtnVal = tObj.return_value + 1000 # return_value keeps a result of
the last proc
label.text format(“Time is #{Time.new.strftime(”%X")}",
*(cnt.divmod(100)))
tRtnVal
}

define the ‘elapsed time’ procedure repeated by the TkTimer object

elapsedProc = proc{|tObj2| #<== TkTimer object
tRtnVal2 = tObj2.return_value + 1000 # return_value keeps a result of
the last proc
label2.text format(“Elapsed is #{(Time.at(Time.new.to_i -
(oldTime.to_i - 18000))).strftime(”%X")}", *(cnt.divmod(100)))
tRtnVal2
}

timer = TkTimer.new(1000, -1, timeProc).start(0, proc{ label.text(‘The
time is …’); 0 })

timer2 = TkTimer.new(1000, -1, elapsedProc).start(0, proc{
label2.text(‘Elapsed time is …’); 0 })

ev_quit = TkVirtualEvent.new(‘Control-c’, ‘Control-q’, ‘q’)

Tk.root.bind(ev_quit, proc{Tk.exit}).focus

Tk.mainloop

From: David B. [email protected]
Subject: Re: Callback For A Timer Event To Display Widget in Ruby/Tk
Date: Tue, 28 Mar 2006 20:17:14 +0900
Message-ID: [email protected]

I have two quick questions: will my creation of all those Time.new
objects (two per second) cause me to run out of resources if I do it for
a long time?

Probably, if you don’t keep any references for those Time objects,
GC will release the resources of those objects.

Secondly, while this ‘elapsed time’ code works:

“Elapsed is #{(Time.at(Time.new.to_i - (oldTime.to_i -
18000))).strftime(”%X")}"

I have a sneaky feeling that it is not the best (Ruby?) way. Is it way
too resource wasteful, and if so, is there a more “Ruby” way?

I think the following returns the same result as yours.

basetime = (Time.now - 18000).to_f # instead of “oldTime”

“Elapsed is #{(Time.now - basetime).strftime(”%X")}"

Hidetoshi NAGAI wrote:

From: David B. [email protected]
Subject: Re: Callback For A Timer Event To Display Widget in Ruby/Tk
Date: Tue, 28 Mar 2006 20:17:14 +0900
Message-ID: [email protected]

I have two quick questions: will my creation of all those Time.new
objects (two per second) cause me to run out of resources if I do it for
a long time?

Probably, if you don’t keep any references for those Time objects,
GC will release the resources of those objects.

Secondly, while this ‘elapsed time’ code works:

“Elapsed is #{(Time.at(Time.new.to_i - (oldTime.to_i -
18000))).strftime(”%X")}"

I have a sneaky feeling that it is not the best (Ruby?) way. Is it way
too resource wasteful, and if so, is there a more “Ruby” way?

I think the following returns the same result as yours.

basetime = (Time.now - 18000).to_f # instead of “oldTime”

“Elapsed is #{(Time.now - basetime).strftime(”%X")}"

H.N.,

Yes, it gives the same results. And it is much cleaner. My method was
a “Brute Force Coding” technique, because I do not understand the Time
class’ methods fully. I shall go back and study it more.

I’m having trouble placing my ‘current time’ and ‘elapsed time’ displays
(TkLabels) where I want them. I’m now studying the Ruby/Tk geometry
manager indirectly via a Perl/Tk book. I haven’t mastered it enough to
ask any intelligent questions yet, though. If I have problems all day,
I may ask you a question tomorrow. In any case, again, thank you for
your gracious assistance.

D.B.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs