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

Hi, I wrote a Perl Tk script (to be used on Windows) that essentially provides the end user with a listbox of choices and a submit button. You select what you want from the listbox and hit Submit. What happens next is I download some files (with Net::Ftp) and extract those files (with Archive::Zip). I repeat that process a few times with different files. While this is happening (the downloading or extracting) the GUI window is pretty much locked up, and you can't move it, etc. I have $mw->update statements in between downloads and extracts, which frees up the GUI momentarily. But how do I make it so I can allow the user to move the GUI around *while* downloads and/or extractions are taking place? I would also like to throw in a "Cancel" button so all of this can be cancelled mid-stream. But hard to do when the window is completely locked up. thanks so much!

Replies are listed 'Best First'.
Re: Perl Tk GUI locking
by runrig (Abbot) on Jun 04, 2007 at 18:57 UTC
    Maybe you could pass a tied filehandle to Net::FTP::hash() that could call $mw->update() which would allow periodic updating of the window during transfer (update: which would take care of the transfer type but sidestep the extraction time issue).

    You could also implement a progress bar this way.

Re: Perl Tk GUI locking
by Fletch (Bishop) on Jun 04, 2007 at 18:44 UTC

    You can't use the convenience wrappers like get, but you should be able to use the methods such as retr which will give you an Net::FTP::dataconn instance that should behave enough like a socket filehandle for you to do your own select and reading calls interspersed with appropriate update calls.

Re: Perl Tk GUI locking
by zentara (Cardinal) on Jun 05, 2007 at 12:20 UTC
    Here is a simple generic example to get you rolling. In the thread, I count to a number ( defaults to 5 ). All you need to do is put your Net::Ftp or LWP code into the thread instead. The test count thing is to show you the main Tk gui is not blocking while the thread runs. This threaded example needs a simple improvement to close the thread when exiting by the window manager's close button.... that should give you something to work out on your own. (By the way, unless you really need Net::Ftp, I suggest using LWP to get your files, since you can setup a progressmeter for big files. Search groups.google.com for "LWP Tk progress" )
    #!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; use Tk; use Tk::ActivityBar; require Tk::Dialog; # setup thread before any Tk code my $go; my $die; my $progress; my $data, share $go; share $progress; share $die; share $data; $go = 0; $progress = 0; $die = 0; $data = 5; # example value to stop search at my $thread = threads->new(\&do_work); my $mw = MainWindow->new(-background => 'gray50'); my $lframe = $mw->Frame( -background => 'gray50',-borderwidth=>10 ) ->pack(-side =>'left' ,-fill=>'y'); my $rframe = $mw->Frame( -background => 'gray50',-borderwidth=>10 ) ->pack(-side =>'right',-fill =>'both' ); my $activity = $lframe->ActivityBar()->pack(-side => 'top',-anchor => +'n'); my $button = $lframe->Button( -text => 'get_file', -background => 'lightgreen', -command => sub { &get_a_worker } )->pack( -side => 'top', -anchor => 'n', -fill=>'x', -pady +=> 20 ); my $text = $rframe->Scrolled("Text", -scrollbars => 'ose', -background => 'black', -foreground => 'lightskyblue', )->pack(-side =>'top', -anchor =>'n'); my $repeat; my $startbut; my $repeaton = 0; $startbut = $lframe->Button( -text => 'Start Test Count', -background => 'hotpink', -command => sub { my $count = 0; $startbut->configure( -state => 'disabled' ); $repeat = $mw->repeat( 100, sub { $count++; $text->insert( 'end', "$count\n" ); $text->see('end'); } ); $repeaton = 1; })->pack( -side => 'top', -fill=>'x', -pady => 20); my $stoptbut = $lframe->Button( -text => 'Stop Count', -command => sub { $repeat->cancel; $repeaton = 0; $startbut->configure( -state => 'normal' ); })->pack( -side => 'top',-anchor => 'n', -fill=>'x', -pady => 20 ) +; my $exitbut = $lframe->Button( -text => 'Exit', -command => sub { $die = 1; $thread->join; if ($repeaton) { $repeat->cancel } exit; })->pack( -side => 'top',-anchor => 'n', -fill=>'x', -pady => 20 + ); #dialog to get file url--------------------- my $dialog = $mw->Dialog( -background => 'lightyellow', -title => 'Get File', -buttons => [ "OK", "Cancel" ] ); my $hostl = $dialog->add( 'Label', -text => 'Enter File Url', -background => 'lightyellow' )->pack(); my $hostd = $dialog->add( 'Entry', -width => 100, -textvariable => '', -background => 'white' )->pack(); $dialog->bind( '<Any-Enter>' => sub { $hostd->Tk::focus } ); my $message = $mw->Dialog( -background => 'lightyellow', -title => 'ERROR', -buttons => [ "OK" ] ); my $messagel = $message->add( 'Label', -text => ' ', -background => 'hotpink' )->pack(); $mw->MainLoop; ####################################### sub get_a_worker { #disable multiple thread starts $button->configure(-state =>'disabled'); # here you can pass data to the thread thru a shared var, # like what value to search for # $data = 5; # simple example $hostd->configure( -textvariable => \$data); if ( $dialog->Show() eq 'Cancel' ) { return } $activity->startActivity(); $go = 1; # start a repeater to watch shared vars my $watcher; $watcher = $mw->repeat(10, sub{ if ($go == 0){ $activity->configure(-value => 0); if ($progress == $data){ $text->insert( 'end', "\t\t\t$progress\n" ); $text->see('end'); } $watcher->cancel; $button->configure(-state=>'normal'); } }); } ################################## sub do_work{ $|++; while(1){ if($die == 1){ goto END }; if ( $go == 1 ){ #do your hash search or whatever foreach my $num (1..100){ $progress = $num; print "\t$num\n"; if( $num == $data ){ $go = 0 } select(undef,undef,undef, .5); if($go == 0){last} if($die == 1){ goto END }; } $go = 0; #turn off self before returning }else { select (undef,undef,undef,.1 ); } #nap time } END: } ###############################################

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      Awesome, thank you so much for the sample code! I should be able to accomplish what I need with this as a resource. thanks!
Re: Perl Tk GUI locking
by Anonymous Monk on Jun 04, 2007 at 18:39 UTC
    Fork or thread
      Any way you could give me some sample code? can pseudo-code the FTPing and extracting. but just to get an idea of where "fork" statements go, and what they look like, and how the flow goes, it would be helpful. Or even a reference? I've tried searching for fork and thread usage, and haven't been able to find anything that appears to be helpful. Anything would be incredibly helpful. I appreciate it very much. Thanks!