<HTML>
<HEAD>
<TITLE>Win32::GUI Tutorial - Part 5 - More than one window</TITLE>
<LINK REV="made" HREF="mailto:">
</HEAD>
<BODY>
<!-- INDEX BEGIN -->
<UL>
<LI><A HREF="#Win32_GUI_Tutorial_Part_5_M">Win32::GUI Tutorial - Part 5 - More than one window</A>
<UL>
<LI><A HREF="#A_simple_multi_window_program">A simple multi-window program</A>
<LI><A HREF="#Main_and_popup_windows">Main and popup windows</A>
<LI><A HREF="#Keeping_popup_windows_alive">Keeping popup windows alive</A>
<LI><A HREF="#Simulating_modal_windows">Simulating "modal" windows</A>
</UL>
</UL>
<!-- INDEX END -->
<HR>
<P>
<H1><A NAME="Win32_GUI_Tutorial_Part_5_M">Win32::GUI Tutorial - Part 5 - More than one window</A></H1>
<P>
<HR>
<H2><A NAME="A_simple_multi_window_program">A simple multi-window program</A></H2>
<P>
Before going further into control details, we'll explore the case of
applications that make use of more than one window.
<P>
In principle, Win32::GUI does not limit the number of windows a program can
have: we've seen that the usual procedure for a program is:
<OL>
<LI>
<P>
create the main window, eg:
<P>
<PRE> $Window = new Win32::GUI::Window(...);
</PRE>
<LI>
<P>
create controls, eg:
<P>
<PRE> $Window->Add...(...);
</PRE>
<LI>
<P>
show the window, eg:
<P>
<PRE> $Window->Show();
</PRE>
<LI>
<P>
call the dialog phase, eg:
<P>
<PRE> Win32::GUI::Dialog();
</PRE>
</OL>
<P>
Steps 1, 2 and 3 can be repeated how many times you like, to create several
independent windows:
<P>
<PRE> use Win32::GUI;
$W1 = new Win32::GUI::Window(
-name => "W1",
-title => "First Window",
-pos => [ 100, 100 ],
-size => [ 300, 200 ],
);
$W2 = new Win32::GUI::Window(
-name => "W2",
-title => "Second Window",
-pos => [ 150, 150 ],
-size => [ 300, 200 ],
);
</PRE>
<P>
<PRE> $W1->Show();
$W2->Show();
Win32::GUI::Dialog();
</PRE>
<P>
the two windows we've created are displayed on the screen and are both able
to intercept events and user interaction, with the rather obvious
limitation that while the code for a window's event is executing, the other
one is frozen; whis is due to the single-threaded nature of Perl, although
work is being done for a full featured multithreaded Perl).
<BR><BR><CENTER><IMG SRC="guitut5-1.gif"></CENTER>
<P>
One thing to note is that even if the windows are two, they belong to the
same process and share a single message loop, so when you exit from one
window (or when the program terminates for whatever reason), they both
disappear:
<P>
<PRE> sub W1_Terminate { return -1; }
</PRE>
<P>
<HR>
<H2><A NAME="Main_and_popup_windows">Main and popup windows</A></H2>
<P>
A much more common case is to have a program using a main window, initially
shown, and one or more popup windows (generally DialogBoxes) that are shown
in response to a precise function; to make an example, you can imagine the
Windows Explorer as your main window and the File Properties dialog as a
popup window.
<P>
We'll modify our program so that the second window appears when the user
clicks the button on the first window:
<P>
<PRE> use Win32::GUI;
$W1 = new Win32::GUI::Window(
-name => "W1",
-title => "Main Window",
-pos => [ 100, 100 ],
-size => [ 300, 200 ],
);
$W1->AddButton(
-name => "Button1",
-text => "Open popup window",
-pos => [ 10, 10 ],
);
$W2 = new Win32::GUI::Window(
-name => "W2",
-title => "Popup Window",
-pos => [ 150, 150 ],
-size => [ 300, 200 ],
);
</PRE>
<P>
<PRE> $W1->Show();
Win32::GUI::Dialog();
</PRE>
<P>
<PRE> sub Button1_Click { $W2->Show(); }
sub W1_Terminate { return -1; }
</PRE>
<P>
Furthermore, we put a button on the second window to make it go away:
<P>
<PRE> $W2->AddButton(
-name => "Button2",
-text => "Close this window",
-pos => [ 10, 10 ],
);
sub Button2_Click { $W2->Hide(); }
</PRE>
<BR><BR><CENTER><IMG SRC="guitut5-2.gif"></CENTER>
<P>
This rather basic example shows the skeleton framework for a typical
multi-window application; but there are still two issues we want to
address: the mortality of popup windows and their ``modal'' behaviour.
<P>
<HR>
<H2><A NAME="Keeping_popup_windows_alive">Keeping popup windows alive</A></H2>
<P>
If you choose to close the second window with the Close (little X) button
on the upper right corner, you'll notice that the window disappear, and
that it does not show anymore when you press the button on the main window!
<P>
What's happening here is that we requested a <CODE>W2_Terminate</CODE> action, and since we didn't provide an event for this, Win32::GUI proceeds
with the default behaviour for the close button, which is to destroy the
window. The result is that you can't show <CODE>$W2</CODE> anymore, because
it does not exists anymore as a valid window (although it still exists as a
Perl object). To let our window survive the close action, we need to
provide a customary <CODE>Terminate</CODE> event:
<P>
<PRE> sub W2_Terminate {
$W2->Hide();
return 0;
}
</PRE>
<P>
The <CODE>return 0</CODE> is <STRONG>very important</STRONG> in this case, because it tells Windows to avoid the destruction of our
window (it is just hidden), so that we can show it again using the button
in <CODE>$W1</CODE>.
<P>
<HR>
<H2><A NAME="Simulating_modal_windows">Simulating "modal" windows</A></H2>
<P>
Here is another very common functionality you may want to implement: when a
popup window is open, you don't want the user to interact with the main
window; this is known as using a ``modal'' window, a window that gets all
your attention and does not let you go forward with the program unless you
have disposed of it.
<P>
Win32::GUI does not have direct support for modal windows, but you can
simulate the behaviour with this trick:
<P>
<PRE> sub W1_Activate {
if($W2->IsVisible) {
$W2->SetForegroundWindow();
return 0;
}
return 1;
}
</PRE>
<P>
The meaning should be obvious enough: if the popup window is shown, trying
to activate the main window automatically reports you to the popup window;
otherwise, the main window becomes the active one as normal. Of course, if
you have more than one popup window, you should add code for everyone of
them:
<P>
<PRE> sub W1_Activate {
if($W2->IsVisible) { $W2->SetForegroundWindow(); return 0; }
if($W3->IsVisible) { $W3->SetForegroundWindow(); return 0; }
# ... and so on
return 1;
}
</PRE>
</BODY>
</HTML>