With regards to fork() and Win32::GUI....

I have been playing with this as well, and while I have not arrived at a
"best practices" I have arrived at a baseline that works. Basically, I fork
the gui thread and then send window messages to it, or, call the appropriate
function on the window object I want to manipulate in a "classless" way.

For example, if you had created a progress bar control, you would normally
call it using

        $progressControl->somefunction();

that is

        $progressControl->SetPos($amount);

As it turns out, and I don't know if Aldo intended for it to work this way,
if you have a handle to the control, you can also call the routine in the
"classless" way by doing

        GUI::ProgressBar::SetPos($progressControlHandle,$amount));

The latter is the way I talk to the controls from the thread that is not
running Win32::GUI::Dialog.

Right now, I am locating the window handle for the dialog itself using
GUI:FindWindow() in the non-gui thread. I'm not happy with this approach,
and am looking at other solutions as well.

Amine Moulay Ramdane's Win32::MemMap package
(http://www.generation.net/~aminer/Perl/) looks like the right solution for
this, at least for me, but I had a problem with it when I tried to use it
and ran out of time to mess with it. I know he recently posted an updated
version, I need to pull that down and see if it still has the same problem.

My initial need was to not have to use GUI::FindWindow() to locate the
dialog and controls. My thought was to serialize a hash in the gui thread
and pass it back to the non gui thread via shared memory - which
Win32::MemMap provides, and unserialize on the non gui side.

You can probably do something similar with pipes, but for some reason, I
thought that the shared memory approach looked better.


I suspect that I've rambled on enough for one day. I've included in this
message a script for a progress bar that runs in a thread by itself taking
positioning commands from another thread.


Oh, by the way, in response to another message on the list today, I think
Win32::MemMap has a timer implementation in it.


Wandering back to the real world.....

--- Tom
Tom Allebrandi
[EMAIL PROTECTED]

#! perl -w

############################################################################
####
############################################################################
####
##
## Subpackage ProgressBar
##
##

package Ta2::UiHelpers::ProgressBar;
require Exporter;
@ISA    = qw(Exporter);
@EXPORT = qw(
        Create
        Destroy
        Set
        );

use Win32::GUI;
use constant CW_USEDEFAULT => 0x80000000;

#
# Reserves ProgressBar in the main namespace for us (uhmmm...)
#
*ProgressBar:: = \%Ta2::UiHelpers::ProgressBar::;

############################################################################
####
#
# Manifest constants
#
use constant TITLE_BAR_HEIGHT => 19;
use constant WINDOW_BORDER    =>  3;
use constant MARGIN           => (7 - WINDOW_BORDER);

############################################################################
####
#
# Create()
#

sub Create
{
#
# Parameters
#
my ($title,$width,$height,$minValue,$maxValue) = @_;

#
# "Local" variables
#
my $handle = 0;
my $i;
my $pid;

#
# Fire off a thread to manage the window
#
$pid = fork();

if (!defined($pid))
        {
        #
        # Failed to fork
        #
        warn("Failed to fork management thread for ProgressBar\n");
        }

 elsif ($pid == 0)
        {
        #
        # We are continuing in the child. Do the progress bar
        #
        doProgressBar($title,$width,$height,$minValue,$maxValue);
        exit(0);
        }

 else
        {
        #
        # We are continuing in the parent. Wait for the window to appear but
        # wait no more than 30 seconds
        #
        $i = 0;

        while (($handle == 0)
           &&  ($i < 30))
                {
                #
                # Look for the window
                #
                if (($handle = GUI::FindWindow("",$title)) == 0)
                        {
                        #
                        # Not found. Pause and try again
                        #
                        sleep(1);
                        $i++;
                        }
                }

        if ($handle == 0)
                {
                warn("Never saw the ProgressBar appear\n");
                }
        }

return($handle);
}

############################################################################
####
#
# Destroy()
#

sub Destroy
{
#
# Parameters
#
my ($handle) = @_;

#
# Tell the window procedure to quit
#
# 0x8001 = WM_EXITLOOP = WM_APP+1
return(GUI::PostMessage($handle,0x8001,-1,0));
}


############################################################################
####
#
# Set()
#

sub Set
{
#
# Parameters
#
my ($handle,$amount) = @_;

#
# The progress bar is the first control on the dialog
#
$handle = GUI::GetDlgItem($handle,0);

#
# Set the new progress amount
#
# 1026 == PBM_SETPOS
return(GUI::ProgressBar::SetPos($handle,$amount));
}

############################################################################
####
#
# doProgressBar()
#

sub doProgressBar
{
#
# Parameters
#
my ($title,$width,$height,$minValue,$maxValue) = @_;

#
# "Local" variables
#
my $progressControl;
my $window;

#
# Create a dialog box to hold the progress bar
#
$window = new Win32::GUI::DialogBox(
        -text           => $title,
        -left           => CW_USEDEFAULT,
        -top            => CW_USEDEFAULT,
        -width          => $width,
        -height         => $height,
        -name           => 'Ta2::UiHelpers::ProgressBarDialog',
        -remstyle       => WS_SYSMENU,
        -remexstyle     => WS_EX_CONTEXTHELP);

if (!defined($window))
        {
        warn("Failed to create ProgressBar dialog\n");
        goto ABORT;
        }

#
# Compute a good size for the progress bar control
#
$width -= (2 * MARGIN) + (2 * WINDOW_BORDER);

$height -= TITLE_BAR_HEIGHT + (2 * MARGIN) + (2 * WINDOW_BORDER);

#
# Put the progress bar on the window
#
$progressControl = $window->AddProgressBar(
        -left   => MARGIN,
        -top    => MARGIN,
        -width  => $width,
        -height => $height,
        -smooth => 1);

if (!defined($progressControl))
        {
        warn("Failed to create ProgressBar control\n");
        goto ABORT;
        }

#
# Set the limits and the initial position
#
$progressControl->SetRange($minValue,$maxValue);
$progressControl->SetPos($minValue);

#
# Put the display on the screen
#
$window->Show();

#
# Activate the dialog
#
Win32::GUI::Dialog();

#
# Take the display off of the screen
#
$window->Hide();

ABORT:
if (defined($window))
        {
        $window->DestroyWindow();
        }
}


############################################################################
####
#
# Support routines
#

sub ProgressBarDialog_Terminate
{
return(-1);
}


############################################################################
####
############################################################################
####
##
## Main program
##
##

#
# "Local" variables
#
my $i;
my $pb;

#
# Create a progress bar
#
$pb = Create("A Progress Bar",200,100,0,30);

#
# Update it once a second for 30 seconds
#
for ($i=0;$i<30;$i++)
        {
        Set($pb,$i);
        sleep(1);
        }

#
# Take away the progress bar
#
Destroy($pb);

exit(0);
__END__


Reply via email to