Knowledge Base |

# How to Create Hidden MDI Child Forms

Article ID: 115781

Article Last Modified on 10/20/2003

APPLIES TO

- Microsoft Visual Basic 3.0 Professional Edition

This article was previously published under Q115781

## SUMMARY

MDI child forms cannot be loaded without being visible, unlike ordinary forms. However, you can use the technique described in this article to make it appear as if loaded MDI child forms are invisible by using form arrays to hide them. Use this technique to provide faster response or configure forms dynamically before making them visible.
The example given below shows you how to:

- Simulate the background of the MDI parent form by using a MDI child form, and then hide other MDI child forms lower in the Z order (the order of a form's precedence along the depth or Z axis).
- Use form arrays to track form status (which forms in the array are presently loaded).

## MORE INFORMATION

The example code creates an MDI child form (named BackSim) to simulate the background of the MDI parent form. The sole purpose of the BackSim MDI child form is to hide the other MDI child forms that lay below it in the Z order. This makes the other child forms appear invisible or hidden, yet remain loaded.
The example gives the BackSim MDI child form the following key property settings:

    Property      Value
    -------------------
    Enabled       False
    ControlBox    False
    Caption       ""
    BorderStyle   0 - None
    MaxButton     False
    MinButton     False

In the MDI parent's Resize event, you can position the BackSim MDI child form to be the exact same size as the MDI parent form. This makes the child form appear identical to the parent form:

    Sub MDIForm_Resize ()
       backsim.Move 0, 0, MDIform1.ScaleWidth, MDIform1.ScaleHeight
    End Sub

### Example Code

Instead of offering this article in a number of steps, we have modified the usual format to make it easier for you to create and use this Visual Basic application. Therefore, the four files you need to create, MDI_SIM.BAS, MDIFORM1.FRM, BACK_SIM.FRM, and SIMCHILD.FRM are listed below so you can easily copy them into a text editor and save them as separate files. Instructions for how to use the files are embedded in the files as comments.

### MDI Parent Form Definition

NOTE: this was developed on a machine run at 1024X768 screen resolution, so some property values may need to be reset for lower-resolution monitors. This can be done in the VB.EXE environment by resizing the forms.

### MDIFORM1.FRM

    ' The following includes the form and control descriptions as well as
    ' necessary Function and Sub procedures. Place this code in a single text
    ' file called MDIFORM1.FRM. so you can load it as a form in Visual Basic.
    '
    ' NOTE: To make the code fit in this article, some of the lines
    ' are listed using multiple lines. After copying the code into a file,
    ' modify it to ensure that each line of code exists as one, single line
    ' in the file. Otherwise, you will receive errors when loading the form in
    ' Visual Basic.

    VERSION 2.00
    Begin MDIForm MDIForm1
       Caption         =   "MDIForm1"
       ClientHeight    =   5412
       ClientLeft      =   948
       ClientTop       =   1908
       ClientWidth     =   7368
       Height          =   6156
       Left            =   900
       LinkTopic       =   "MDIForm1"
       Tag             =   "Parent"
       Top             =   1212
       Width           =   7464
       Begin Menu mnu_children
          Caption         =   "&Children"
          Begin Menu mnu_newchild
             Caption         =   "&New Child"
             Shortcut        =   ^N
          End
          Begin Menu mnu_unloadall
             Caption         =   "&Unload All Children"
             Shortcut        =   ^U
          End
       End
       Begin Menu mnu_Window
          Caption         =   "&Window"
          Begin Menu mnu_cascade
             Caption         =   "&Cascade"
             Shortcut        =   ^C
          End
          Begin Menu mnu_tileh
             Caption         =   "Tile &Horizontal"
             Shortcut        =   ^H
          End
          Begin Menu mnu_tilev
             Caption         =   "Tile &Vertical"
             Shortcut        =   ^V
          End
          Begin Menu mnu_sim
             Caption         =   "Simulated &Background"
             Index           =   0
             Shortcut        =   ^B
          End
          Begin Menu mnu_showall
             Caption         =   "Show &All Children"
             Shortcut        =   ^A
          End
       End
    End

    Sub MDIForm_QueryUnload (Cancel As Integer, unloadmode As Integer)
       ' Unload all child forms loaded at runtime:
       mnu_unloadall_Click
    End Sub

    Sub MDIForm_Resize ()
       ' This reference to the properties of the BackSim
       ' MDI child form causes Visual Basic to implicitly load
       ' the form. Because MDI child forms cannot be loaded
       ' without being visible, this shows the BackSim form:
       backsim.Move 0, 0, MDIform1.ScaleWidth, MDIform1.ScaleHeight
    End Sub

    Sub mnu_cascade_Click ()
       backsim.ZOrder 1
       MDIform1.Arrange 0 ' cascade
       tiledflag = 0
    End Sub

    Sub mnu_newchild_Click ()
       ' Increment counter for array of child forms:
       childcount = childcount + 1

       ' Decide if new array slots are needed
       ' or if old (unloaded) slots need to be filled
       ' First, do empty slots exist:
       If childcount <= trackcount Then
          ' Find empty slot in arrays (menu and childtrack):
          lowestfreenum = 1
          For i = 1 To UBound(childtrack)
             If Not childtrack(i) Then
             lowestfreenum = i
             Exit For
             End If
          Next i
          ' Mark slot as loaded:
          childtrack(lowestfreenum) = True
          ' Load a new menu item for each child form
          ' under the menu control mnu_sim(0):
          Load mnu_sim(lowestfreenum)

          ' Set a new caption for the new menu item and supply access key:
          ' Turn the following two lines into one, single line:
          mnu_sim(lowestfreenum).Caption =
             "Show Only Child Form Number &" & lowestfreenum
          ' Mark this slot as loaded:
          childtrack(lowestfreenum) = True

          ' Set the tag equal to the childcount
          ' to allow tracking of self:
          child_array(lowestfreenum).Tag = lowestfreenum

          ' Set unique caption for each child form to cause an
          ' implicit load and show the child form:
          ' Turn the following two lines into one, single line:
          child_array(lowestfreenum).Caption =
             "Child Form Number " & lowestfreenum
       Else
          ' Create new slot:
          trackcount = trackcount + 1
          ' Increase size of both arrays:
          ReDim Preserve childtrack(1 To trackcount)
          ReDim Preserve child_array(1 To childcount)
          ' Load a new menu item for each child form
          ' under the menu control mnu_sim(0):
          Load mnu_sim(trackcount)

          ' Set a new caption for the new menu item and supply access key:
          ' Turn the following two lines into one, single line:
          mnu_sim(trackcount).Caption =
             "Show Only Child Form Number &" & trackcount

          ' Mark this slot as loaded:
          childtrack(trackcount) = True

          ' Set the tag equal to the childcount
          ' to allow tracking of self:
          child_array(trackcount).Tag = trackcount

          ' set unique caption for each child form
          ' this causes implicit load and shows child
          child_array(trackcount).Caption = "Child Form Number " & trackcount

       End If
    End Sub

    Sub mnu_showall_Click ()
       ' Place simulated background form at the bottom of the Z order:
       backsim.ZOrder 1

       ' Bring all the loaded child forms to the top of the Z order in
       ' succession:
       For i = 1 To trackcount
          If childtrack(i) Then
             If Not child_array(i).Enabled Then child_array(i).Enabled = True
             child_array(i).ZOrder 0
             child_array(i).Caption = child_array(i).Caption
          End If
       Next i
       Exclusive = False
    End Sub

    Sub mnu_sim_Click (index As Integer)

       ' Special case: if the arrange method has tiled the child windows,
       ' reset arrangement to cascade to get ZOrder method to work:
       If tiledflag Then
          MDIform1.Arrange 0  ' cascade
          tiledflag = False
       End If

       If index = 0 Then
          ' User wants to clear all children from MDI form
          ' but does not want to unload them:
          backsim.ZOrder 0
          ' Disable minimized form to avoid system menu popup:
          For i = 1 To trackcount 'UBound(childtrack)
             If childtrack(i) Then
                If child_array(i).WindowState = 1 Then
                   child_array(i).Enabled = False
                End If
             End If
          Next i
       Else

          ' Bring the simulated background to the top
          ' of the Z order to hide all other children:
          backsim.ZOrder 0
          ' Disable minimized form to avoid system menu popup:
          For i = 1 To UBound(childtrack)
             If childtrack(i) Then
                If child_array(i).WindowState = 1 Then
                   child_array(i).Enabled = False
                End If
             End If
          Next i

          ' Bring desired child form to the top:
          child_array(index).ZOrder 0
          child_array(index).Enabled = True
          child_array(index).Caption = child_array(index).Caption
          child_array(index).SetFocus
          ' Set flag for QueryUnload event of child form
          ' to avoid a repaint over the next child form in
          ' Z order if unload current "only" child:
          Exclusive = True
       End If
    End Sub

    Sub mnu_tileh_Click ()
       backsim.ZOrder 1
       MDIform1.Arrange 1 ' Tile horizontal.
       tiledflag = 1
    End Sub

    Sub mnu_tilev_Click ()
       backsim.ZOrder 1
       MDIform1.Arrange 2 ' Tile vertical.
       tiledflag = 2
    End Sub

    Sub mnu_unloadall_Click ()
       ' Unload all child forms marked
       ' as loaded in childtrack array:
       For i = 1 To trackcount ' UBound(childtrack)
          If childtrack(i) Then
             Unload child_array(i)
          End If
       Next i
       ' Reset counters:
       trackcount = 0
       childcount = 0
    End Sub

### BACK_SIM.FRM

    ' The following includes the form and control descriptions as well
    ' as necessary Function and Sub procedures. Place the code in a
    ' single text file called BACK_SIM.FRM, so you can load it as a form
    ' in Visual Basic.

    VERSION 2.00
    Begin Form backsim
       BackColor       =   &H00C0C0C0&
       BorderStyle     =   0  'None
       ClientHeight    =   4776
       ClientLeft      =   1632
       ClientTop       =   1644
       ClientWidth     =   7368
       ControlBox      =   0   'False
       Enabled         =   0   'False
       Height          =   5196
       Left            =   1584
       LinkTopic       =   "Form2"
       MaxButton       =   0   'False
       MDIChild        =   -1  'True
       MinButton       =   0   'False
       ScaleHeight     =   4776
       ScaleWidth      =   7368
       Tag             =   "BackSim"
       Top             =   1272
       Width           =   7464
    End
    Sub Form_Load ()
       ' Set the backcolor property to match
       ' whatever system color setting the user has set
       ' for the Background color of multiple document
       ' interface (MDI) applications:
       Me.BackColor = GetSysColor(COLOR_APPWORKSPACE)
    End Sub

### SIMCHILD.FRM

    ' The following includes the form and control description as well as
    ' necessary Function and Sub procedures. Place the code in a single text
    ' file called SIMCHILD.FRM, so you can load it as a form in Visual Basic.

    VERSION 2.00
    Begin Form ftemplate
       Caption         =   "ftemplate"
       ClientHeight    =   6300
       ClientLeft      =   1116
       ClientTop       =   1224
       ClientWidth     =   7368
       Height          =   6720
       Left            =   1068
       LinkTopic       =   "Form3"
       MDIChild        =   -1  'True
       ScaleHeight     =   6300
       ScaleWidth      =   7368
       Top             =   852
       Width           =   7464
    End
    Sub Form_QueryUnload (cancel As Integer, unloadmode As Integer)
       ' Remove menu item pointing to Me:
       Unload mdiform1.mnu_sim(Val(Me.Tag))
       ' Mark my slot as unloaded:
       childtrack(Val(Me.Tag)) = False
       ' Decrement total childcount:
       childcount = childcount - 1

       ' If this form was the only child form visible
       ' at the time of unload, put background
       ' form the top of the z order:
       If Exclusive Then
          ' Must enable background form temporarily
          ' so that it will be the next in the Z order
          ' after the unload. This avoids a repaint over
          ' the previous child in the Z order.
          backsim.Enabled = True
          backsim.ZOrder 0
          backsim.Enabled = False
          Exclusive = False
       End If
    End Sub

    Sub Form_Resize ()
       ' Keep minimized children visible by
       ' setting the ZOrder explicitly:
       If Me.WindowState = 1 Then
          Me.ZOrder 0
          ' Force repaint of caption:
          Me.Caption = Me.Caption
       End If
    End Sub

### How to Create and Run the Program

1. Start a new project in Visual Basic. Form1 is created by default.
2. From the File menu, choose Remove File, and remove Form1.
3. From the File menu, choose Add File, and add MDIFORM1.FRM
4. Repeat step 3 to add BACKSIM.FRM and SIMCHILD.FRM to the project.
5. From the Options menu, choose Project, and set the Start Up Form to MDIFORM1.
6. Create a new module (MDI_SIM.BAS) and add the following code to the general declarations section:

          Global child_array() As New ftemplate
          Global childtrack() As Integer
          Global childcount As Integer, trackcount As Integer
          Global lowestfreenum As Integer, i  As Integer
          Global Exclusive As Integer, tiledflag As Integer

          Declare Function GetSysColor Lib "User" (ByVal nIndex%) As Long

          Global Const COLOR_APPWORKSPACE = 12

7. Save the project and run the program. Exercise all the menu options, close or minimize the child forms. Note that the program tracks the state of the child forms and recycles slots in the form array, which is based on the ftemplate form (SIMCHILD.FRM). Substitute your own child form for the ftemplate form. Transplant the essential code from ftemplate to your child form, and determine if the benefits of being able to have hidden child forms are worth the extra code.

Additional query words: 3.00

Keywords: KB115781