Visual Basic Window/Form Routines
Simulating Owned Windows for MDI Children
Posted:   Monday October 01, 2001
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   None
Author:   VBnet - Randy Birch

"Normal" (non-MDI apps) applications use the second parameter of a form's Show command to specify that the calling form will "own" the second form; that is, the second form remains above the calling form similar to a modal dialog, yet allows activity to take place on either form.

MDI applications behave differently. Only the MDI parent form can own another form, be it a MDI child, a modal dialog or a form where the parent was set as the Owner param. When a MDI application shows a form whose Owner parameter is specified, the only valid value for the Owner parameter is the MDI Parent form.

Thus, when a developer needs to show a popup form (henceforth called "the Dialog") in a MDI application, either a modal form or a MDI Parent-owned form must be used.  Modal forms in MDI applications defeat the very concept of MDI - that the user has the ability to switch between open MDI children at will. Displaying a modal form forces the user to complete actions on that form and close it in order to use other MDI children.

Should the developer opt instead to use the Owner parameter and code so the Dialog form is owned by the MDI parent, the Dialog, which only has relevance to the currently-active MDI child, becomes both screen clutter when the user switches to another MDI child (as the Dialog remains on-screen), as well as a possible point of application error when data is errantly entered into a visible Dialog that may not be relevant to the current MDI child form, yet appears to be owned by the active form since the Dialog floats over the MDI parent.

This demo shows how to maintain the principles of MDI while providing individual copies of the Dialog form for each MDI child requiring such, and how to code the those dialogs so that only the dialog for the currently-active MDI child form is displayed on screen. As the user moves from one MDI child from to another, previously displayed Owned forms are hidden, while the Owned form pertaining to the active child is displayed. This code was inspired by a newsgroup request for a means to provide multiple dialogs for data entry that behaved modally, yet still allowed the user to move between MDI child forms. 

The principle used is fairly straightforward and frankly, explaining it takes longer than creating the demo.  The MDI parent has a button to load a new copy of a base MDI child Form1, using the standard "Dim x as New Form1" syntax.  Each Form1 has a button that will display a dummy Dialog form.  Multiple Form1's can be opened, and for each Form1, a corresponding Dialog can also be opened. The rules of VB dictate that each of the Dialog forms shown is owned (can only be owned) by the MDI parent form, so through the use of custom properties in both Form1 and the Dialog code the demo shows how to set up properties and methods that assure only the dialog owned by the currently-active Form1 is on-screen, hiding any other open Dialog forms that are owned by other Form1's that do not have focus. As the user switches between the different open Form1 children, the corresponding dialog, if loaded, reappears on-screen, while the previous dialog disappears. And as a bonus, all this is done in straight VB without APIs.

The demo consists of three forms - the MDI Parent (MDIForm1), a MDI Child (Form1), and a dialog form (Dialog). There can be multiple Form1's, and any or all Form1 forms can have and own its own corresponding Dialog form.

 BAS Module Code

 MDI Parent Form Code "MDIForm1"
To the MDI parent form - MDIForm1 - add a picturebox as a container and place into it two command buttons (Command1, Command2), along with the following code:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
Private Sub Command1_Click()

  'define and load a new copy of
  'Form1 as a MDI Child
   Dim f As Form
   Set f = New Form1
  'this is just used to assist in
  'identifying the forms and their
  'owned dialogs.
   Static cnt As Long
   cnt = cnt + 1
   f.Tag = f.Name & " - number " & cnt
   f.Caption = f.Tag
End Sub

Private Sub Command2_Click()

  'tile the open Child forms
  'in the MDI workspace
   MDIForm1.Arrange 1
End Sub
 MDI Child Form Code "Form1"
To the MDI child form - Form1 - add a command button (Command1) and the following code:

Option Explicit
'HasDialog property variable
Private m_dialogshowing As Boolean

'holds reference to the owned dialog
Private myDlg As Form

Public Sub ClearDialogParams()

  'a routine called by the owned dialog to
  'reset the variables as it unloads
   m_dialogshowing = False
   Set myDlg = Nothing

End Sub

Private Sub Command1_Click()

  'Create a new copy of the shared dialog form
   Set myDlg = New Dialog
   Load myDlg
  'Set the property of this form to
  'reflect the form has opened a
  'dialog it wants to own
   HasDialog = True
  'Required: set the Tag property of the
  'owned dialog to the current form
  'tag - in this case the form title.
  'This allows us to know which form owns
  'the dialog.
   myDlg.HasOwner = Me.Tag
  'for debug only: set the caption on the owned dialog
   myDlg.Caption = "This dialog owned by : " & myDlg.HasOwner
  'Show the form. Remember that all forms,
  'both MDI children and non-MDI forms, are
  'actually owned by the MDI parent window.
  'Attempting to set the Owner parameter to
  'the MDI Child form will generate an error
  'as a MDI child can not be used as an owner
  'for a Show command.
   myDlg.Show vbModeless, MDIForm1
End Sub

Private Sub Form_Activate()

   SetDialogState True
End Sub

Public Function SetDialogState(state As Long)

  'if this form has opened an owned dialog,
  'then set the state of the dialog according
  'to the activation state of the MDI Child
  'form. When the form has focus, the owned
  'dialog is shown. When the form loses focus
  'to another MDI Child, the owned dialog
   If HasDialog() Then
      myDlg.Visible = state
   End If
End Function

Public Property Get HasDialog() As Boolean

  'True if MDI Child has opened a
  'dialog window, or false if not.
   HasDialog = m_dialogshowing
End Property

Private Property Let HasDialog(ByVal vNewValue As Boolean)

   m_dialogshowing = vNewValue
End Property

Private Sub Form_Deactivate()

   SetDialogState False

End Sub

Private Sub Form_Unload(Cancel As Integer)

  'since the child is unloading might as well 
  'unload any owned dialog as well
   If HasDialog() Then Unload myDlg  
End Sub
 Non-MDI Dialog Form Code - "Dialog"
Add a non-MDI form to the project, name it Dialog, and add two command buttons to the form (Command1, Command2). These buttons do nothing but unload the form, and are placeholders for actual OK or Cancel buttons. Once set up, add the following code to Dialog:

Option Explicit
Private m_ownedby As String

Private Sub CancelButton_Click()

  '<code for Cancel>
   Unload Me

End Sub

Private Sub OKButton_Click()

  '<code for OK>
   Unload Me

End Sub

Public Property Get HasOwner() As String
  'HasOwner will be empty ("") if no
  'owner, or will contain the owner's
  'window caption
   HasOwner = m_ownedby

End Property

Public Property Let HasOwner(ByVal vNewValue As String)

   m_ownedby = vNewValue
End Property

Private Sub Form_Unload(Cancel As Integer)

   Dim f As Form
  'if this form is owned by a MDI Child
   If Len(HasOwner) > 0 Then
     'iterate through the open forms collection
      For Each f In Forms
        'if the tag property of the form
        'equals the value of the m_ownedby
        'variable, then we found the
        'MDI Child form that owns this dialog
        'form, so execute that MDI Child's
        'ClearDialogParams routine to reset
        'working variables before unloading.
        'This allows the MDI Child to again
        'show a new dialog as an owned form.
         If f.Tag = m_ownedby Then
            f.Enabled = True
         End If
   End If
End Sub
Set the project start-up properties to MDIForm1, assure Form1 has its MDI Child property set to True, and run. Open several Form1 copies using the "Show New Form1" button.  Hit the Tile button to arrange the forms for easier testing, then press the "Open Owned Dialog" button on one form.  Move the dialog to another spot on the screen, and click on one of the other Form1 copies. The dialog form will disappear until the form that owned (created) the dialog is selected, at which point it will again appear on-screen at the last location.  Press the  "Open Owned Dialog" buttons on other forms, and again, move the forms a bit so you can see that different forms are activated as each MDI child form becomes active.


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter