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

Greetings: I am new to PERL (1 year) but even newer to TK (1 week or so). Here is my problem...... I have a PERL program that creates a nice window, adds some radio buttons, a status Label widget, and a 'go' Button. What I am wanting to do -- when the 'go' Button is clicked, the program will disable the radio buttons, get the directory listing from differnt directories, and update the Label widget with the number of files found. What happens is the main window freezes until the all the directories have been parsed. Note the code snippet below has a lot of the overhead removed. I don't think it will run on its own. Sorry if it is forbidden to post unworking code. I just wanted everyone to see the setup.
use Tk; # TK Setup #Window Creation $main = MainWindow -> new(); #Create Main Window Object $main -> minsize(qw(500 250)); #Size window $main -> configure(-background => 'blue');#Set Background Color #add go button $button_1 = $main -> Button(-text => "GO", -padx => 25, -foreground => "white", -background => "green", -command => \&go)-> pack(-side => 'bottom', -anchor => + 's', expand => 'yes'); #Add main center frame $left_3 = $main -> Frame(-relief => 'groove', -borderwidth => 3, -background => 'blue')-> pack(-side => 'botto +m',-anchor => 'n', -fill => 'x'); #added buttons to the frames (removed for this) #add label to center frame $label_3 = $left_3 -> Label(-text => "Status", -background => 'blue', -relief => 'raised', -borderwidth => 3, -foreground => 'white')->pack(-fill => 'x', -anchor => + 'w', expand => 1); $text = $left_3->Label(-textvariable => \$var)->pack(-anchor => ‘w’); + MainLoop(); sub go { #freeze the selections for $i (1..6){$check_button[$i] -> configure(-state => 'disabled') +;} # get info from dictionary files while(($folder, $drive) = each %search_locations) { #get list of files in directory $var = "Looking in - $drive/DICT/SOURCE\n"; chdir "$drive/variable/DICT/SOURCE"; @file_list = glob ("*.dsf"); $var = “Num of files: $#file_list”; } }
I hope this makes sense. What I am wanting is for $var to change in the Label widget as the program processes the while loop. Some other notes, the directories are large (>1000 files). To me, it seems the program is hung during the glob function. The only time the main window updates is when the while loop is complete. Thoughts? keep in mind..newbie here...so.. be nice with the criticism....

Replies are listed 'Best First'.
Re: Newbie with a TK question
by g0n (Priest) on Jan 25, 2006 at 19:29 UTC
    Your label widget '$text', needs to be updated. If you put:

    $text->update;

    in the while loop, it should update the content of the label as $var changes.

    --------------------------------------------------------------

    "If there is such a phenomenon as absolute evil, it consists in treating another human being as a thing."

    John Brunner, "The Shockwave Rider".

      AWESOME...Thank you very much..that was it!!!!
Re: Newbie with a TK question
by thundergnat (Deacon) on Jan 25, 2006 at 19:41 UTC

    Since you have given non-runnable code, it is more difficult to offer useful advice. A few things come to mind however.

    If you want the window to update while a long subroutine is running, you'll need to force it. Put the line $main->update; inside your while loop, probably after each time you want a change to display (each time you modify $var.)

    I do have some other commentary. It is highly recommended you put use warnings; and use strict; at the top of your script, at least while you are developing it and especially if you are relatively inexperienced with perl.

    Make sure you are using the right quote marks. You have some angled single quotes and angled double quotes in there demarking text. They mean something very different from straight single and double quotes to perl. (Well, some of them do, some have NO meaning to perl.)

    To change the states of the check buttons, iterate over them implicitly rather than explicitly.

    $_ -> configure(-state => 'disabled') for @check_button;
    rather than
    for $i (1..6){$check_button[$i] -> configure(-state => 'disabled');}
    also, you may want to re enable them at the end of the subroutine.

Re: Newbie with a TK question
by zentara (Cardinal) on Jan 25, 2006 at 19:49 UTC
    the main window freezes until the all the directories have been parsed.

    Well think about it, the program's execution pointer is busy devoting full time to parsing the directories, so the window-gui seems to lock up. This is one of the most common problems faced when doing GUI's, so don't feel bad.

    There are many solutions. The simplest solution is to liberally sprinkle "$mw->update" throughout your directory parsing sub, like:

    # get info from dictionary files while(($folder, $drive) = each %search_locations) { #get list of files in directory $mw->update; $var = "Looking in - $drive/DICT/SOURCE\n"; chdir "$drive/variable/DICT/SOURCE"; $mw->update; @file_list = glob ("*.dsf"); $mw->update; $var = “Num of files: $#file_list”; }
    That may be excessive, but everytime you call $mw->update, your gui will get some processor time.

    The other options involve forking off your dir-processing and using Tk::fillevent to read the results, in a non-blocking manner. You can also do the same thing with threads.

    So it depends how how much time passes in the lines between each $mw->update. If they are on your local machine, it's probably fast, but if it's over a network link, it may be slow. So then you may have to use fileevent, forks and/or threads. Generally in a GUI, you never use "while(1)" or "sleep", because it blocks the gui.

    Your problem is usually called "blocking the gui", and you can google for "Tk non blocking" to see the myriad of situations and solutions, people have used talked about, regarding blocking the gui.


    I'm not really a human, but I play one on earth. flash japh