tame1 has asked for the wisdom of the Perl Monks concerning the following question:
Obviously this is rudimentary and wrong. i.e I know I somehow need feedback from the system call, and I need to use it to feed the $percent_done, and I also need to know how to "refresh" when the next directory is started. Can anyone provide me with a pointer in the right direction?foreach my $dir (@SOURCE) { next if ($dir eq any(@exclusion_list)); my $mw = MainWindow->new; # Don't use existing window. my $cmd = "cp -a $home_value\/$dir $storage"; while (system($cmd)) { my $progress = $mw->ProgressBar( -width => 200, -height => 20, -from => 0, -to => 100, -blocks => 10, -colors => [0, 'green', 50, 'yellow' , 80, 'red'], -variable => \$percent_done ); } }
Edited by planetscape - changed pre to code tags
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Tk::ProgressBar and system cp
by liverpole (Monsignor) on Nov 21, 2006 at 21:45 UTC | |
A couple of things. You only need to construct your progress bar once. You then manage it by making changes to the variable (in your case, $percent_done). I had never used Tk::ProgressBar before (I usually just construct my own), so I just tried it, and it's quite easy. Here's an example that's pretty close to yours, except that it doesn't try to examine files from an array (like @SOURCE), but rather, for purposes of example, just changes the value of $percent_done:
The delay loop is caused by the code select(undef, undef, undef, 0.1);. It's important to issue an update to the main window with $mw->update();, otherwise you may never see the meter updating. All you need to do is put your code in the subroutine main_loop (or whatever you change its name to), and make sure that you update the percentage variable $percent_done in a meangful way. For example, if you're going by number of files processed $nprocessed, out of a total number of file $total, then $percent_done should be calculated something like: $percent_done = 100 * $nprocessed / $total. A final note: In my experience, you may get a smoother progress meter if you go by total bytes rather than total files, especially in cases where some files are tiny, and some are huge. The way to do this is make $total equal to the total bytecount (from all the files), and $nprocessed the running count of bytes processed. Then the same formula should apply. Good luck! s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/ | [reply] [d/l] [select] |
|
Re: Tk::ProgressBar and system cp
by andyford (Curate) on Nov 21, 2006 at 21:50 UTC | |
I haven't use Tk in many years, so I'm no help there, but you will probably need to start by replacing "cp -r" with a combination of File::Find and File::Copy. The modules should give you the control you need to stop periodically and report your progress to the GUI. There's cpan module too: File::Copy::Recursive. non-Perl: Andy Ford | [reply] |
|
Re: Tk::ProgressBar and system cp
by zentara (Cardinal) on Nov 22, 2006 at 13:52 UTC | |
Beyond that you have some serious obstacles to overcome in your understanding of how the Tk event loop works, and integrating it with an external program, or a pure perl callback. You also chose a particularly tricky task to perform, because there is no easy way to get a running callback without IPC. You also have the problem of monitoring bytes-transferred vs. file-count. Additionally, the Tk::ProgressBar is a slow widget, and it will not be able to keep up with a fast copy. (shown below). First, don't create a new mainwindow in your loop, you will gain memory that way. Create 1 mainwindow and work with it. Second, will block the Tk gui from working, until the system command is done. There are so many ways to approach this, that it is hard to decide which is best. Probably andyford 's idea of a combination of File::Find and File::Copy would be the best. That way would involve first resetiing your progressbar, as you entered each directory, counting the files and totaling their bytes, then copy each file 1 by 1, subtracting the bytes transferred from the total bytes and updating the progressbar. While this would be accurate, it will slow down the actual copy. Another alternative, would be to run your system command thru IPC::Open3, and update the progressbar in the *READ callback. Then you could run cp with the -v option, to get a printout of each file as it is transferred. So for each line you read, you update progress by 1. So here are 2 scripts to show the problem. The first uses IPC to make a fast copy, but then the progressbar can't keep up, and you get "deep recursion errors". The second, will give a good progress display, but it is slow and uses too much cpu. So ...... I think you are wasting time trying to write a script like that. I didn't try a threaded version, but I think the result would be the same.... just slowing everything down. You might be able to get away with it, if you only update the progressbar every 10th or 100th increment. Read more... (4 kB) | [reply] [d/l] [select] |
|
Re: Tk::ProgressBar and system cp
by tame1 (Pilgrim) on Nov 22, 2006 at 16:28 UTC | |
Here is the final product (I didn't use IPC or even File::Find, as they didn't really seem as simple as I needed).
Again, thanks to everyone. This version seems to run very smoothly (it copies an 87 level deep directory structure in less than a minute, progress bar and all). The progress bar comes up when and where I want it, it goes away when it's complete, and there is even a nice "OK moron, I'm done" message window. If anyone thinks this a really stupid way to do this, please feel welcome to redo it in "better" perl and post to the code section of perlmonks. I used to code a lot of perl (even did it for a living around the turn of the century) but now I only do one or two scripts a year, so as you can see I am very very rusty. Improvements are always welcome. What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY" | [reply] [d/l] [select] |