Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Perl:TK - standard output to text widget

by crabbdean (Pilgrim)
on Feb 27, 2004 at 18:39 UTC ( #332324=perlquestion: print w/replies, xml ) Need Help??

crabbdean has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

Most simple perl programs are scripts run at the command line. To make them look a little more professional I'm writing a simple "standard gui" module with TK so that the scripts run in a nice gui style window. Its mostly written. But I have one problem I haven't been able to solve ...

Basically I want to capture STDOUT to a text-like widget. Now STDOUT is a stream, directed somewhere, for example to the terminal. I want to direct this to my text widget. I'm guessing I need to create a reference type glog of the STDOUT to my text-widget? Or open a filehandle to it or a pipe? Or call a subroutine in a loop that reads the STDOUT and appends it to the text-widget? As you can tell I'm not sure. Help?!

The bare guts of the code is below. Thoughts/comments/suggestions?

use Tk; use Tk::Pane; my $mw = MainWindow->new (-title => 'sgui'); $mw->resizable('false','true'); my $run = $mw -> Button(-text => 'Run!', -width => 27, -command => [\&that] ); my $enter = $mw->Label(-text => "\nOutput"); my $pane = $mw->Scrolled("Pane", Name => 'fred', -scrollbars => 'osoe', -sticky => 'we', -width => 540, -height => 580 ); my $text = $pane->Text(-width => 75, -height => 40); my $quitButton = $mw->Button ( -text => 'Quit', -width => 27, -command => \&quit); $enter->pack; $pane->Frame; $pane->pack; $text->pack; $text->insert('end', \*STDOUT); $quitButton->pack; MainLoop;

Replies are listed 'Best First'.
Re: Perl:TK - standard output to text widget
by bbfu (Curate) on Feb 27, 2004 at 21:25 UTC

    You can tie STDOUT to a Tk::Text object to have anything printed in perl appear in the text widget. This doesn't handle input, of course, nor does it work with any external programs you might call (for those, see the previous suggestions).

    #!/usr/bin/winperl use warnings; use strict; use Tk; my $mw = MainWindow->new(); my $tx = $mw->Text()->pack(); tie *STDOUT, 'Tk::Text', $tx; $mw->repeat(1000, \&tick); MainLoop; my $count; sub tick { ++$count; print "$count\n"; }

    Black flowers blossom
    Fearless on my breath

      Man you are no less than a God!!! What a brilliant solution. Very clever. Something I didn't even consider. Works a treat. Now I just have to solve the other little myriad of problems and see if I can come up with a nice modular solution.

      Its getting closer bit by bit.

        merlyn pointed out that this feature is undocumented. Thus, it might be subject to change, not 100% reliable, etc. I haven't personally used it much, so I can't vouch for its reliability, either. If you have to use it in production code, you should keep a good test suite that you can re-run after every update.

        Black flowers blossom
        Fearless on my breath

Re: Perl:TK - standard output to text widget
by matija (Priest) on Feb 27, 2004 at 19:07 UTC
    Capture the STDOUT, sure. But STDOUT of what?

    If it is output from your own script, do yourself a favor, and simply change all the relevant print statements with calls to a routine that appends to the widget.

    If not, are you trying to catch the output of some command that completes quickly? (like, say, man or ls)

    In that case, use $var=`command` to capture the stdout of the command into your variable.

    If it is the output of a program that will take a while to execute, and produce output at various points in time, then you should open that program with a pipe, like so:

    open(COM,"command |") || die "Could not execute command\n";
    . In the last case you will have to arrange something that will check for new output on a regular basis. File::Tail may be of some use with that.
Re: Perl:TK - standard output to text widget
by kvale (Monsignor) on Feb 27, 2004 at 19:10 UTC
    If you want to dump all output to the text object, try the backticks command:
    my $out = `command`; $text->insert('end', $out);
    If you want to process things line by line, try opening a pipe:
    open OUT "command |" or die "Could not open command: $!\n"; while (my $line = <OUT>) { # process $line ... $text->insert('end', $line); }


Re: Perl:TK - standard output to text widget
by zentara (Archbishop) on Feb 28, 2004 at 16:40 UTC
    I'm not sure what your project entails, but if you are using Tk, it would be good to be aware of fileevent. It gives you non-blocking reads.
    #!/usr/bin/perl use warnings; use strict; use Tk; my $mw = new MainWindow; my $t = $mw->Text(-width => 80, -height => 25, -wrap => 'none'); $t->pack(-expand => 1); open(CHILD, "./read-stdout-piper 2>&1 |") or die "Can't open: $!"; $mw->fileevent(\*CHILD, 'readable', [\&fill_text_widget,$t]); MainLoop; sub fill_text_widget { my($widget) = @_; $_ = <CHILD>; if((defined $_) && ($_ > 5)){print chr(07)} $widget->insert('end', $_); $widget->yview('end'); }
    And the sender script
    !/usr/bin/perl $|++; for my $i ( 0 .. 10) { print $i, "\n"; sleep 1; } print "sleeping 5\n"; sleep 5; for my $i ( 0 .. 10) { print $i, "\n"; sleep 1; }

    I'm not really a human, but I play one on earth. flash japh
      Now how can I modify this program to do a tail on a file. I have multiple tables in my main GUI window and need to tail the summary, detail and error file! I am stuck so any help would be greatly appreciated! Thanks in advance!
        You are better off getting rid of the tie to STDOUT, that is a hack of last resort. :-)

        Look at this. You could open multiple IPC connected filehandles, watch them with multiple fileevents, and insert the output into the same text widget, with different colored text.

        #!/usr/bin/perl use strict; use Tk; use IO::Handle; my $H=IO::Handle->new; open($H,"tail -f -n 50 z.txt |") or die $!; my $main = MainWindow->new; my $t = $main-> Scrolled('Text', -wrap=>'none')->pack(-expand=>1); $main->fileevent(\*$H,'readable',[\&fill,$t]); MainLoop; sub fill { my ($w) = @_; my $text; my $text =<$H>; $w->insert('end',$text); $w->yview('end'); }

        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://332324]
Approved by Grygonos
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (1)
As of 2021-10-21 23:58 GMT
Find Nodes?
    Voting Booth?
    My first memorable Perl project was:

    Results (85 votes). Check out past polls.