http://www.perlmonks.org?node_id=503549

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

Hi Pals..... I have an issue with creating progressbar using Tk::ProgressBar. The issue goes like this:
My current application is already using Tk to display a window but my application consumes around one minute and finally displays the result in that window. It means that I am already calling MainLoop() to display this window which is an infinite loop. I want to display a progressbar for that one min gap. I am unable to use Tk::ProgressBar since calling MainLoop for progressbar will cause my application to stuck at that point. So , I guess i cannot call MainLoop twice in a single application.
To summarise: -> I need to display a progress bar before displaying my result window. Issue is , since I am already calling MainLoop for displaying window, I cannot use Tk::ProgressBar because it also needs MainLoop.

Thnx in advance.

Replies are listed 'Best First'.
Re: Using Tk::ProgressBar
by Courage (Parson) on Oct 28, 2005 at 10:28 UTC
    $widget->update
    is your friend; you can create toplevel for it, in case you do not have to show your mainwindow.
Re: Using Tk::ProgressBar
by radiantmatrix (Parson) on Oct 28, 2005 at 14:27 UTC

    There are a couple of approaches here. All of them require an understanding that MainLoop is just an event loop. That means factoring your code in such a way that it does small chunks of operation at a time. For example:

    #instead of: for (1..100000) { sleep 1; } $mw->update(); #do for (1..100000) { sleep 1; $pb->update($_); #update progressbar $mw->upddate(); }

    One approach is to make a progress bar in your MainWindow, then when finished delete the bar and populate the MainWindow with the widgets that display your results.

    Another is to have a "status bar" type area in your results window, show your results window immediately, but with all but the status bar "greyed out" (disabled) until you finish calculating results.

    Both of the above only require one MainLoop.

    Another approach, and one I'm a big fan of, is to refactor your application as a POE app, and use POE's event loop (which encapsulates a Tk event loop) to manage the various components of your application.

    All that said, there is no reason your result window has to be the MainWindow. You could just as easily create a sub window that's displayed near the end of the MainLoop.

    How about some code you've tried?

    <-radiant.matrix->
    A collection of thoughts and links from the minds of geeks
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law
Re: Using Tk::ProgressBar
by neosamuri (Friar) on Oct 28, 2005 at 06:13 UTC
    I beleive that you will need to use threads to allow the ProgressBar to be displayed with the main loop while doing the work that your application needs to do.

    UPDATE: Just realized that you would need threads::shared in order for this method to work.

    I am sure that there are better ways of doing this, but I am not sure what
      using threads for GUI for Tk is very wrong. Achieve nothing, and will render program unstable.
      Yet, threads in perl are unusable.
        Threads and Tk,are NOT wrong, but they have to be done with alot of care. You cannot mix Tk code across threads, and all threads must be created before any Tk code is invoked in the main thread. See Tk-with-worker-threads or this simple example:
        #!/usr/bin/perl use strict; use threads qw[ async ]; use threads::shared; our $WORKMAX ||= 1_000; #by BrowserUk ## A shared var to communicate progess between work thread and TK my $progress : shared = 0; sub work { for my $item ( 0 .. $WORKMAX ) { { lock $progress; $progress = ( $item / $WORKMAX ) * 100; } select undef, undef, undef, 0.001; ## do stuff that takes t +ime } } threads->new( \&work )->detach; ## For lowest memory consumption require (not use) ## Tk::* after you've started the work thread. require Tk::ProgressBar; my $mw = MainWindow->new; my $pb = $mw->ProgressBar()->pack(); my $repeat; $repeat = $mw->repeat( 100 => sub { print $progress; $repeat->cancel if $progress == 100; $pb->value($progress); } ); $mw->MainLoop;

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