Hi Wiggins,
Tk is not thread safe, so you should not expect to be able to manage a gui from two threads in the same process.
However, that shouldn't stop you from doing ALL gui management from within one thread (preferrably the parent), and setting up a worker thread to handle otherwise potentially-blocking actions (such as LWP fetches). For that, you may want to look at using threads::shared.
To do this, construct the thread before setting up the gui. I've created an example program for you which illustrates this:
#!/usr/bin/perl -w
# Always use 'strict' and 'warnings'
use strict;
use warnings;
# Libraries
use threads;
use threads::shared;
use Thread::Queue;
use Tk;
use Tk::ROText;
# Globals
my $rotext = 0; # The Read-only text widget
my $n_lines_waiting: shared = 0; # Message passing between thre
+ads
my $p_queue = Thread::Queue->new(); # Construct message 'Queue'
####################
### Main program ###
####################
# Startup worker thread
my $gui_thr = threads->create(\&worker_thread);
# Only *now* is it safe to construct the GUI, from the parent thread
gui();
+
###################
### Subroutines ###
###################
# This subroutine is ONLY called from the parent thread
sub gui {
my $mw = MainWindow->new();
my $top = $mw->Frame()->pack(-expand => 1, -fill => 'both');
my $bt = $top->Button(-bg => 'skyblue', -text => "Exit");
$bt->configure(-command => sub { $mw->destroy() });
$rotext = $top->ROText(-bg => 'white');
$rotext->pack();
$bt->pack();
$mw->repeat(1000 => \&main_loop);
MainLoop;
}
sub main_loop {
if ($n_lines_waiting) {
fetch_worker_data();
}
}
sub fetch_worker_data {
for (my $i = 0; $i < $n_lines_waiting; $i++) {
my $line = $p_queue->dequeue();
$rotext->insert("end", "$line\n");
}
$rotext->insert("end", "--- End of $n_lines_waiting line(s) ---\n"
+);
$rotext->see("end");
my $mw = $rotext->toplevel();
$mw->update();
$n_lines_waiting = 0;
}
# This subroutine is ONLY called in the worker thread
sub worker_thread {
while (1) {
sleep 3;
worker_simulate_data();
}
}
sub worker_simulate_data {
my $nlines = int(rand(10));
($nlines > 0) or return;
my $timestamp = localtime(time);
for (my $i = 0; $i < $nlines; $i++) {
my $idx = $i + 1;
my $line = "[$timestamp] Random line of text #$idx";
$p_queue->enqueue($line);
}
$n_lines_waiting = $nlines;
}
The subroutine worker_simulate_data is called by the worker_thread subroutine every 3 seconds, and creates from 0 to 9 lines of data, which are then queued using Thread::Queue. Finally, the shared variable $n_lines_waiting is set to the number of lines waiting in the queue.
The parent thread gets the signal of how many lines are waiting via $n_lines_waiting, pulls this number of lines out of the shared queue, and writes them to the ROText window $rotext.
Note that the worker thread only writes new data if $n_lines_waiting is zero (otherwise there are lines waiting which haven't been read by the parent thread yet).
Of course, you are free to do other operations within the main_loop, as well as modify worker_thread so that it uses real-life data rather than a simulation.
s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
|