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

Dear monks, I would like to insert a program's output to a Tk::Text widget, but some times the program uses \r to refresh one line. While this seems ok when sent to a terminal, in the Tk::Text widget I get a lot of useless output filling my text widget. Is there a simple way to emulate the terminal (stripping \r's and refreshing?) I am using fileevent to get the program's output Thank you in advance

Replies are listed 'Best First'.
Re: inserting program output in Tk::Text
by liverpole (Monsignor) on May 05, 2007 at 17:32 UTC
    Hi diamantis,

    If I understand you correctly, you're seeing some kind of progress indicator or meter; something which looks fine in the terminal window (because each line overwrites previous lines), but of course it looks bad in the Tk::Text window, just as it would if the terminal window displayed each line of text on a separate physical line.

    A couple of suggestions come to mind.  First off, if you don't need the \r separated lines, just throw them away.  If the status they're giving you is helpful, you could always parse them, and use the indication to update some actual status meter (such as you'd get with Tk::StatusBar or Tk::ProgressBar).

    Another option would be to use tags in the Text window, and each time you receive output which would have overwritten the previous line, have the Text widget erase the previous line and replace it with the new one, to achieve the same effect.

    Of these two, my choice would be to go with the first; it's more in the spirit of GUIs in general, and Perl/Tk specifically.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: inserting program output in Tk::Text
by graff (Chancellor) on May 06, 2007 at 01:38 UTC
    To follow up a bit on the suggestion about just removing the useless output from the text:
    # supposing the program output is all stored in $text: $text =~ s/.*\r//g;
    Since "." won't match a "\n" (and Tk::Text does the right thing with "\n" in its display), the above regex will retain the original line count of the program output, and on each line, it removes everything up to and including the right-most "\r", leaving only the text that follows from that point to the next "\n" (which is all that would have been visible in a normal terminal display).

    update: And as for actually making Tk::Text emulate a normal terminal display, you would need to keep track of the current line number in the text buffer (where the next chunk of program output will go), something like this:

    # you need to know which line number you're at in the Tk::Text buffer # -- let's suppose that's in a variable called "$line_number" @updates = split( /\r/, $latest_output ); for my $string ( @updates ) { $tktext_widget->SetCursor( "$line_number.0" ); # go to start of +that line; $tktext_widget->deleteToEndofLine; $tktext_widget->Insert( $string ); $line_number += ( $string =~ tr/\n// ); }
    That's a bit klugey because if one chunk of data from the program containins a lot of "\r"s, it does lots of changes to the widget's text content that won't be seen by the user. But it ought to work as intended, I think. (another update: fixed typo on "+=")