in reply to Posting thread data in a Perl/Tk window

# the following 3 lines of code would be invoked by a button press $thr=threads->new(\&sub_name);

I see a glaring mistake here. In Tk threaded apps, you MUST create the threads BEFORE any Tk code is invoked, or you will get thread-safety problems. Since you are invoking the thread from a Button, you already are risking thread safety. Just see threads: spawn early to avoid the crush. or search here for "Tk threads" and see how all the examples create the threads right before any Tk is called. So what you will need to do, is start your SerialPort stuff in the thread first, possible sitting in a while loop, waiting for a signal to start. THEN have a Tk Button that sets a shared variable to signal the while loop to start execution. I have an example at Tk-with-worker-threads.

Also, remember, that you can share the serial port filehandle through a thread by it's fileno.

#!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; use Tk; my %shash; #share(%shash); #will work only for first level keys my %hash; share ($shash{'go'}); share ($shash{'fileno'}); share ($shash{'pid'}); share ($shash{'die'}); $shash{'go'} = 0; $shash{'fileno'} = -1; $shash{'pid'} = -1; $shash{'die'} = 0; $hash{'thread'} = threads->new(\&work); my $mw = MainWindow->new(-background => 'gray50'); my $text = $mw->Scrolled('Text')->pack(); my $repeater; my $buf; my $startb = $mw->Button( -text => 'Start', -command=>sub{ $shash{'go'} = 1; $mw->after(1000); my $fileno = $shash{'fileno'}; print "fileno_m $fileno\n"; open (my $fh, "<&=$fileno") or warn "$!\n"; while(<$fh>){ $text->insert('end',$_); $text->see('end'); $mw->update; } # $repeater = $mw->repeat(10, # sub { # my $bytes = sysread( $fh, $buf, 8192); # $text->insert('end',$buf); # $text->see('end'); # if( $shash{'go'} == 0 ){ $repeater->cancel } # } # ); } )->pack(); my $stopb = $mw->Button( -text => 'Stop', -command=>sub{ exit; }, )->pack(); MainLoop; ################################################################## sub work{ $|++; while(1){ if($shash{'die'} == 1){ goto END }; if ( $shash{'go'} == 1 ){ my $pid = open(FH, "top -b |" ) or warn "$!\n"; my $fileno = fileno(FH); print "fileno_t->$fileno\n"; $shash{'fileno'} = $fileno; $shash{'go'} = 0; #turn off self before returning }else { sleep 1 } } END: } ###################################
Also, you can setup your serial port and read it from a Tk timer, but threads will give you more Start/Stop control. Here is an old newsgroup post.
======== On Jul 2, 7:46 am, zentara <zent...@highstream.net> wrote: > On Sun, 01 Jul 2007 16:20:57 -0700, pnbe...@gmail.com wrote: > >I don't know what I am doing but I do know what I want. > >I am trying write a small Perl/Tk program that takes the data prese +nt > >on /dev/ttyS0 and displays it in a Label widget. > > >All that happens is I get a Perl/Tk window that displays "Weigh- > >Tronix /dev/ttyS0" rather than the actual scale weight. What am I > >missing here? > >Thanks for any help. > >Paul > > As felix said, you are just displaying the name of the serialport. > > You need to open the serial port and read it like a filehandle. > As you read the filehandle, you can update the label, but unless the > messages are extremely short, you may be better off displaying it in + a > Text widget. > > Here is a super-simple way of reading the serial port. I'm using the > Object Oriented Device::Serial port, but you can also try to read th +e > port with filehandle directly (but it can be a hassle). > > use warnings; > use strict; > use Tk; > use Device::SerialPort; > > #my $serial_port = "/dev/ttyS0"; > my $serial_port = new Device::SerialPort ("/dev/ttyS0") || die "can' +t > open COM1\n"; > > #Setup Perl/Tk > my $mw = MainWindow->new(); > $mw->title("Scale"); > > #Close button > my $button = $mw->Button( > -text => 'Close', > -command => sub {$mw->destroy} # exit is better here > )->pack( > -pady => 20, > -side => 'bottom' > ); > > my $title_label = $mw->Label( > -text => "Weigh-Tronix" > )->pack( > -side => 'left'); > > my $input = '---------------'; > my $display_label = $mw->Label( > -textvariable => \$input, > -width=>15, #keep the width stable at 15 > )->pack( > -side => 'left'); > > # every 100 millisecs update from port > $mw->repeat(100, sub{ > $input = $port->input; > if(defined $port->input){ $input = $port->input } > > }); > > MainLoop; > > __END__ > > zentara > > -- > I'm not really a human, but I play one on earth.http://zentara.net/j +aph.html Thank you very much for the leads. I read up on filehandles in the Camel book and came up with the following code that does work: use warnings; use strict; use Tk; my $serial_port = "/dev/ttyS0"; open(SERIAL, "<$serial_port"); my $scale_weight = <SERIAL>; #Setup Perl/Tk my $mw = MainWindow->new(); $mw->title("Scale"); #Close button my $button = $mw->Button( -text => 'Close', -command => sub {$mw->destroy} )->pack( -side => 'bottom' ); my $title_label = $mw->Label( -text => "Weigh-Tronix" )->pack( -side => 'left', -pady => 5, -padx => 5 ); my $display_label = $mw->Label( -textvariable => \$scale_weight )->pack( -side => 'left', -pady => 5, -padx => 5 ); MainLoop; I will investigate the Device::SerialPort package and thank you very much for the example on getting the program to refresh the display, I was wondering how to do that! Paul

I'm not really a human, but I play one on earth. Cogito ergo sum a bum