Re: Perl Tk Asynchronous Progress Updates
by BrowserUk (Patriarch) on Jul 01, 2013 at 20:32 UTC
|
| [reply] |
|
|
my $button=$mw->Button(-text=>'Update');
$button->after(0, [\&update, \$prog ]);
$button->pack;
$mw->ProgressBar(-variable=>\$prog)->pack;
For some reason the callback function is now executed immediately after the script is run (and still not asynchronously), rather than after the button event. Any help would be much appreciated.
Thanks
| [reply] [d/l] |
|
|
| [reply] [d/l] [select] |
|
|
Re: Perl Tk Asynchronous Progress Updates
by kcott (Archbishop) on Jul 02, 2013 at 04:10 UTC
|
G'day hermes1908,
Welcome to the monastery.
I don't think your users would be too happy having to manually update the download progress by pressing a button.
This is really something you'd want to display dynamically.
Consider how it's done in a simple text-based scenario (e.g. wget) or in a graphical context such as your browser: you don't need to hit keys or press buttons to see what progress has been made.
When designing a GUI, think about how it's been done previously and how your users would expect it to work.
Unless you are intending to present something that is fundamentally different from the norm, stick with the status quo.
Here's a working (albeit barebones) script that simulates 3 files being downloaded simultaneously and shows progress dynamically.
#!/usr/bin/env perl
use strict;
use warnings;
use Tk;
use Tk::ProgressBar;
my @file_data = (
{ name => 'File1', size => 1000 },
{ name => 'File2', size => 5000 },
{ name => 'File3', size => 2500 },
);
my $mw = MainWindow->new();
$mw->geometry('400x200+50+50');
my $control_F = $mw->Frame()->pack(-side => 'bottom');
$control_F->Button(-text => 'Exit', -command => sub { exit }
)->pack(-padx => 5, -pady => 5);
my $progress_F = $mw->Frame(
)->pack(-padx => 10, -pady => 10, -fill => 'both', -expand => 1);
for my $file_datum (@file_data) {
my $download_amount = 0;
my $download_percent;
my $download_F = $progress_F->Frame(
)->pack(-padx => 10, -pady => 10, -side => 'top', -fill => 'x'
+);
$download_F->Label(-text => $file_datum->{name}
)->pack(-padx => 5, -side => 'left');
$download_F->ProgressBar(-variable => \$download_percent
)->pack(-padx => 5, -side => 'left', -fill => 'x', -expand =>
+1);
$download_F->repeat(25 => sub {
$download_amount += int rand 10;
if ($download_amount > $file_datum->{size}) {
$download_amount = $file_datum->{size};
}
$download_percent = $download_amount / $file_datum->{size} * 1
+00;
});
}
MainLoop;
| [reply] [d/l] [select] |
|
|
Thanks for the example, but the idea was that I would prompt the user for input (using an entry widget) and then initiate the download. The updates are supposed to be asynchronous so a button doesn't need to pushed to see the progress. The idea is that once a download has been initiated the update function should run in the background so as not to hang up the application (the download link is retrieved via an entry widget). Your sample code has the same issue that mine did, namely that the download routine runs before the gui is even displayed. Do you have the same issue when you run your code? Perhaps something is wrong with my version of Tk ( though I've had this problem on two different machines running different linux distributions, so that's unlikely).
| [reply] |
|
|
use Tk;
use Tk::ProgressBar;
my $mw = MainWindow->new();
my $per = 0;
$mw->ProgressBar(-variable=>\$per)->pack;
$mw->Button(-text=>"Go",-command=>\&GoForIt)->pack;
MainLoop;
######### This is the important bit ###########
sub GoForIt {
$mw->repeat(25=>sub{$per+=10;return if $per>100;;$mw->update;sleep
+(1)})
}
| [reply] [d/l] [select] |
|
|
What you're describing doesn't make any sense to me: I can't see how the (simulated) downloads in my code could have possibly run before the GUI is displayed.
When you ran my code, did you really see all progress bars showing completion? I see them starting at the far left and moving towards the right.
Did you change my code before running it? I can't think of any reason why the code I posted would not run, as is, under Linux; however, if you did change it, please show the actual code you are running.
| [reply] |
|
|
|
|
|
|
| [reply] [d/l] [select] |
Re: Perl Tk Asynchronous Progress Updates
by Khen1950fx (Canon) on Jul 02, 2013 at 02:34 UTC
|
Maybe this will save you time:
#!/usr/bin/perl
use strict;
use warnings;
use Tk;
use Tk::ProgressBar;
my $mw = MainWindow->new(-title => 'ProgressBar example');
my $percent_done = '';
my $progress = $mw->ProgressBar(
-width => 30,
-from => 0,
-to => 100,
-blocks => 50,
-colors => [0, 'red', 50, 'white' , 80, 'blue'],
-variable => \$percent_done
)->pack(-fill => 'x');
$mw->Button(-text => 'Go!', -command=> sub {
foreach (my $i = 0; $i < 1000; ++$i) {
$percent_done = $i/10;
print "$i\n";
$mw->update;
}
})->pack(-side => 'bottom');
MainLoop;
Google for some more examples. Good luck. | [reply] [d/l] |
|
|
Thanks, but my problem is not in using the progressbar widget (I can do this successfully), but in making the callback which updates it execute asynchronously. My update function is more complicated than a simple for loop (as in your example) and takes a while to run (so I need the application to be responsive in the mean time).
| [reply] |
|
|
The example that I gave you can be used with threads ideally,
eg., using the button in each of your threads. It shouldn't
detract from your application's responsiveness. Yes, you'll need to understand threads:-).
| [reply] |
|
|
|
|