how to use Ruby / Tk to display a text message status box

  • Thread starter SpringFlowers AutumnMoon
  • Start date
S

SpringFlowers AutumnMoon

how can we pop up a Tk window to display the temporary results of a
program?

If our program is running and displaying its intermediate calculations,
instead of showing the final result at the end, i hope to have a Tk
window just to show the semi-final results.

would there be a simple way, just using a text box or something?

right now i have:

require 'tk'

root = TkRoot.new {title "Ex1"}
TkLabel.new(root) do
text "Hello, world!"
pack("padx"=> 15, "pady" => 15, "side" => "left")
end
Tk.mainloop

[and my program]

but the program won't run until i close the Tk window generated.
 
A

Alex Fenton

SpringFlowers said:
how can we pop up a Tk window to display the temporary results of a
program?

The normal way to do this is in a GUI program is to use Threads ...
right now i have:
....
Tk.mainloop

[and my program]

but the program won't run until i close the Tk window generated.

When you call "mainloop", you're telling Tk (and other GUIs, too) to
wait for the user to do something (eg click a button). This is sometimes
called an "event loop". As the "loop" name suggests, the program stops
at this point and nothing further will be run until the GUI is ended.

To run other tasks (such as your calculation) concurrently with the
event loop, start those other tasks in a ruby Thread alongside the GUI
code. Then, if you want to display intermediate results from that task
in the GUI, pass messages between the task thread to the main GUI
thread. Again, there's numerous different ways to do this.

I haven't used Ruby Tk so I'm not sure if it's an issue, but in many
other toolkits, the non-GUI threads may starved of execution time - ie
the GUI event loop hogs the scheduler. So if you are finding your
background task is not progressing, you may need to set up a timed event
in the Tk code that passes control among the Threads (eg calling
Thread.pass)

hth
alex
 
S

SpringFlowers AutumnMoon

When you call "mainloop", you're telling Tk (and other GUIs, too) to
wait for the user to do something (eg click a button). This is sometimes
called an "event loop". As the "loop" name suggests, the program stops
at this point and nothing further will be run until the GUI is ended.

To run other tasks (such as your calculation) concurrently with the
event loop, start those other tasks in a ruby Thread alongside the GUI
code. Then, if you want to display intermediate results from that task
in the GUI, pass messages between the task thread to the main GUI
thread. Again, there's numerous different ways to do this.

what about not calling the MainLoop but just keep on painting on the GUI
window? For example, like in Win 32, I had a program that just popped
out a window and then I just keep on using DrawText to paint the result.
The whole program doesn't need to have any event driven handling. just
drawing text to a window.
 
M

Morton Goldberg

what about not calling the MainLoop but just keep on painting on
the GUI
window? For example, like in Win 32, I had a program that just popped
out a window and then I just keep on using DrawText to paint the
result.
The whole program doesn't need to have any event driven handling.
just
drawing text to a window.

Since you propose an alternative solution, why did you not try it out
for yourself, rather than just throwing the question out on the
mailing list? You would have had the answer much quicker hat way.
Ruby is a very easy language to experiment with. That is one of its
greatest strengths. You should take advantage of it -- it is the best
way to learn.

If you had tried your idea, you would have found that it doesn't
work. Unless Tk.mainloop is called, Tk will never paint any windows
on the screen. The advice you received from Alex Fenton was good
advice. If handling threads is too difficult for you at the current
stage of your Ruby development, I suggest you print intermediate
results to stdout.

Regards, Morton
 
S

SpringFlowers AutumnMoon

Morton said:
Since you propose an alternative solution, why did you not try it out
for yourself, rather than just throwing the question out on the
mailing list? You would have had the answer much quicker hat way.
Ruby is a very easy language to experiment with. That is one of its
greatest strengths. You should take advantage of it -- it is the best
way to learn.

because i have no clue how that can be done. all the examples in a book
i found and on the web all do the MainLoop.

that is in the realm of Ruby / Tk and maybe someone knows a couple of
lines that can do it, or some code segment on a page.
 
M

Morton Goldberg

because i have no clue how that can be done. all the examples in a
book
i found and on the web all do the MainLoop.

For the very good reason that there is no other way to make Ruby/Tk
to display anything.
that is in the realm of Ruby / Tk and maybe someone knows a couple of
lines that can do it, or some code segment on a page.

I very much doubt it. I will be happy to be proven wrong.

Regards, Morton
 
S

Summercool

how can we pop up aTkwindow to display the temporary results of a
program?

If our program is running and displaying its intermediate calculations,
instead of showing the final result at the end, i hope to have aTk
window just to show the semi-final results.

someone in the Tcl/Tk newsgroup posted a program to do that.
i don't know the exact Ruby / Tk equivalent right now, but here is the
code that will work in Perl:

use warnings;
use strict;
use Tk qw/tkinit DoOneEvent exit DONT_WAIT ALL_EVENTS/;
use POSIX qw(strftime);

my $mw = tkinit;

my $text=$mw->Text()->pack();


my $I;
my $J = 0;

while (1) {
$mw->DoOneEvent( DONT_WAIT | ALL_EVENTS );
if ( ++$I > 10000 ) { #slows things down use 1 for max speed

$text->delete("1.0", 'end');
$text->insert('end',"And this is GUI $J ");
my $now_string = strftime "%a %b %e %H:%M:%S %Y", localtime;
$text->insert('end',"\ntime is $now_string ");

print "command line $J ";
$I = 0;
$J++;
}
}
 
S

SpringFlowers AutumnMoon

SpringFlowers AutumnMoon wrote:

If our program is running and displaying its intermediate calculations,
instead of showing the final result at the end, i hope to have aTk
window just to show the semi-final results.

the following program can do what the Perl program can do.
right now i don't know Tk enough to check when the GUI window is closed
by the user and therefore don't do any text update.

require 'tk'

tk = TkRoot.new
text = TkText.new(tk).pack()

i = 0
n = 10000

while i += 1
TclTkLib.do_one_event(TclTkLib::EventFlag::ALL |
TclTkLib::EventFlag::DONT_WAIT)
if i % n == 0
text.delete('1.0', 'end')
text.insert('end', "This is GUI %d \n" % (i / n))
text.insert('end', "Time is %s" % Time.now.strftime("%Y-%m-%d
%I:%M:%S"))
printf "This is command line %d ", i / n
end
end
 
H

Hidetoshi NAGAI

Hi,

From: SpringFlowers AutumnMoon <[email protected]>
Subject: Re: how to use Ruby / Tk to display a text message status box
Date: Wed, 26 Sep 2007 21:08:44 +0900
Message-ID: said:
the following program can do what the Perl program can do.
right now i don't know Tk enough to check when the GUI window is closed
by the user and therefore don't do any text update.

How about the following?
----------------------------------------------------------------
require 'tk'

evloop = Thread.new{Tk.mainloop}
text = TkText.new(Tk.root).pack

i = 0
n = 10000

Tk.root.protocol:)WM_DELETE_WINDOW){
if Tk.messageBox:)type=>'okcancel', :message=>' Realy? ') == 'ok'
printf "Bye ...\n"
exit
else
#ignore
end
}

while (text.exist? rescue false)
if (i += 1) % n == 0
text.value = <<EOS
This is GUI #{(i / n)}
Time is #{Time.now.strftime("%Y-%m-%d %I:%M:%S")}
EOS
printf "This is command line #{i / n}\n"
end
end
 
S

SpringFlowers AutumnMoon

Hidetoshi said:
How about the following?
----------------------------------------------------------------
require 'tk'

evloop = Thread.new{Tk.mainloop}
text = TkText.new(Tk.root).pack

i = 0
n = 10000

Tk.root.protocol:)WM_DELETE_WINDOW){
if Tk.messageBox:)type=>'okcancel', :message=>' Realy? ') == 'ok'
printf "Bye ...\n"
exit
else
#ignore
end
}

while (text.exist? rescue false)
if (i += 1) % n == 0
text.value = <<EOS
This is GUI #{(i / n)}
Time is #{Time.now.strftime("%Y-%m-%d %I:%M:%S")}
EOS
printf "This is command line #{i / n}\n"
end
end

That's looking great. I don't know why but the line

while (text.exist? rescue false)

is not getting through (the text.exist? won't be true).

right now i tweak a little bit of it and just make it

while (1)

and still tweaking it.
 
M

Morton Goldberg

How about the following?
----------------------------------------------------------------
require 'tk'

evloop = Thread.new{Tk.mainloop}
text = TkText.new(Tk.root).pack

i = 0
n = 10000

Tk.root.protocol:)WM_DELETE_WINDOW){
if Tk.messageBox:)type=>'okcancel', :message=>' Realy? ') == 'ok'
printf "Bye ...\n"
exit
else
#ignore
end
}

while (text.exist? rescue false)
if (i += 1) % n == 0
text.value = <<EOS
This is GUI #{(i / n)}
Time is #{Time.now.strftime("%Y-%m-%d %I:%M:%S")}
EOS
printf "This is command line #{i / n}\n"
end
end

I had a little trouble when I tried to run your code. I kept getting
a segment fault at the point the code called the exit method. Maybe
it's because I'm still running Ruby 1.8.2 on Mac OS X, and it
wouldn't happen I had a new version of Ruby. However, I did get it to
run by moving the exit call to come after the Tk.mainloop message and
adding a Tk.root.destroy message to block given to the protocol method.

<code>
require 'tk'

tk_event_thread = Thread.new do
Tk.mainloop
puts "Bye..."
exit
end

progress_msg = TkText.new(Tk.root).pack

Tk.root.protocol:)WM_DELETE_WINDOW) {
if Tk.messageBox:)type=>'okcancel', :message=>'Really?') == 'ok'
Tk.root.destroy
end
}

i = 0
loop do
i += 1
progress_msg.value = <<TEXT
This is GUI output #{i}
Time is #{Time.now.strftime("%Y-%m-%d %I:%M:%S")}
TEXT
puts "This is command line output #{i}"
sleep(1)
end
</code>

But thanks very much for posting your code. I learned several
important new things about Ruby/Tk from it.

Regards, Morton
 
S

SpringFlowers AutumnMoon

This is one example with Tk.mainloop running as a thread, and a
reporting loop running as a thread. I can't pass "i" into the
report_and_sleep as "i" points to a constant instance of Fixnum. Needed
to create a counter object so that a reference to the counter instance
is passed, and the thread and extract the value from it:


require 'tk'

tk = TkRoot.new
text = TkText.new(tk, 'width'=>80, "height" => 60).pack()

class Counter
attr_accessor :i
end

i = 0
n = 300000

counter = Counter.new()

Tk.root.protocol:)WM_DELETE_WINDOW){
if Tk.messageBox:)type=>'okcancel', :message=>'Really exit? ') == 'ok'
printf "Bye ...\n"
exit
else
# ignore
end
}

def report_and_sleep(text, counter)
c = 0
time_start = Time.now
while 1
c += 1
sleep 3
text.value = <<EOS
This is report #{c}

This is GUI
The counter is #{counter.i}
It is doing #{(counter.i / (Time.now - time_start)).to_i} iterations per
second
Time is #{Time.now.strftime("%Y-%m-%d %I:%M:%S")}
EOS
end
end


evloop = Thread.new{ Tk.mainloop }
ev_report = Thread.new(){ report_and_sleep(text, counter) }

while (1)

i += 1
counter.i = i
if i % n == 0
printf "This is command line #{i / n} "
end
end
 
S

SpringFlowers AutumnMoon

If however, you don't want a separate reporting thread, this is it:


require 'tk'

tk = TkRoot.new
text = TkText.new(tk, 'width'=>80, "height" => 60).pack()

#text = TkText.new(Tk.root).pack

i = 0
n = 100000

Tk.root.protocol:)WM_DELETE_WINDOW){
if Tk.messageBox:)type=>'okcancel', :message=>'Really exit? ') == 'ok'
printf "Bye ...\n"
exit
else
# ignore
end
}

evloop = Thread.new{ Tk.mainloop }
while (1)

i += 1
if i % n == 0
text.value = <<EOS
This is GUI #{(i / n)}
Time is #{Time.now.strftime("%Y-%m-%d %I:%M:%S")}
EOS

printf "This is command line #{i / n} "
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top