Site:  Cours VB.net  
4.4 Travailler sur une fenêtre multi document.

Comment créer un programme MDI (Multi Document Interface) en VB 2003 puis en VB 2005 ?

Comprendre les programmes MDI :

L’exemple de Word : la fenêtre principale (fenêtre MDI) contient les menus en haut, on peut ouvrir plusieurs documents dans des fenêtres filles.

Ci dessous l'exemple de LDF (Programme de comptabilité écrit par l'auteur):

On a une fenêtre MDI (conteneur) contenant 2 fenêtres filles affichant chacune une année de comptabilité.

 

Dans VB.NET, un MDIForm (fenêtre principale MDI) est une fenêtre quelconque dont la propriété :

IsMDIContainer = True.

Dans la fenêtre fille, la propriété MDIParent indique le conteneur (C'est à dire le nom de la fenêtre MDI) .

 

Les applications MDI peuvent avoir plusieurs conteneurs MDI.

 

Une fenêtre principale MDI peut contenir plusieurs fenêtres filles de même type ou de type différente.

A - En VB 2003

Création de la fenêtre conteneur parent :

Exemple d'un programme MDI.

On va créer une Form1 qui est le conteneur.

Une Form2 qui est la fenêtre fille.

Dans Form1 le menu principal contient la ligne '&Nouvelle' qui crée une nouvelle instance de la fenêtre fille.

Créer la fenêtre Form1 :

Dans la fenêtre Propriétés, affectez la valeur True à la propriété IsMDIContainer. Ce faisant, vous désignez la fenêtre comme le conteneur MDI des fenêtres enfants.

 Remarque   Affecter la valeur Maximized à la propriété WindowState, car il est plus facile de manipuler des fenêtres MDI enfants lorsque le formulaire parent est grand. Sachez par ailleurs que le formulaire MDI parent prend la couleur système (définie dans le Panneau de configuration Windows).

Ajouter les menus du conteneur :

A partir de la boîte à outils, faire glisser un contrôle MainMenu sur le formulaire. Créer un élément de menu de niveau supérieur en définissant la propriété Text avec la valeur &File et des éléments de sous-menu appelés &Nouvelle et &Close. Créer également un élément de menu de niveau supérieur appelé &Fenêtre.

Dans la liste déroulante située en haut de la fenêtre Propriétés, sélectionnez l'élément de menu correspondant à l'élément &Fenêtre et affectez la valeur true à la propriété MdiList. Vous activez ainsi le menu Fenêtre qui permet de tenir à jour une liste des fenêtres MDI enfants ouvertes et indique à l'utilisateur par une coche la fenêtre enfant active.

Il est conseillé de créer un module standard  qui contient une procédure Main qui affiche la fenêtre principale:

Module StandartGénéral

Public FrmMDI as Form1

Sub Main()

    FrmMDI.ShowDialog()

End sub

End Module

 Noter bien que FrmMDI est donc la fenêtre conteneur et est Public donc accessible à tous.

Création des fenêtres filles :

Pour créer une fenêtre fille, il suffit de donner à la propriété MDIParent d'une fenêtre le nom de la fenêtre conteneur.

Dessiner dans Form2 les objets nécessaire dans la fenêtre fille.

Comment créer une instance de la fenêtre fille à chaque fois que l'utilisateur clique sur le menu '&Nouvelle'?

En premier lieu, déclarez dans le haut du formulaire Form1 une variable nommée MDIFilleActive qui contient  la fenêtre fille active.

Dim MDIFilleActive As Form2

La routine correspondant au MenuItem &Nouvelle  (dans la fenêtre MDI) doit créer une instance de la fenêtre fille :

Protected Sub MDIChildNouvelle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click

   MDIFilleActive = New Form2()

   'Indique à la fenêtre fille son ‘parent’.

   MDIFilleActive.MdiParent = Me

   'Affiche la fenêtre fille

   MDIFilleActive.Show()

End Sub

 

Comment connaître la fenêtre fille active? 

Quand on en a ouvert plusieurs?

La fenêtre fille active est dans Me.ActiveMdiChild du conteneur

Comment voir s'il existe une fenêtre active?

If Not Me.ActiveMdiChild Is Nothing then    'elle existe

En  mettant dans la variable MDIFilleActive la fenêtre active, on est sûr de l'avoir toujours à disposition: pour cela dans la procédure Form1_MdiActivate de la fenêtre MDI (qui se produit à chaque fois que l'on change de fenêtre fille) je récupère Me.ActiveMdiChild qui retourne la fenêtre fille active.

Dans Form1

Private Sub Form1_MdiChildActivate..

    MDIFilleActive=Me.ActiveMdiChild

End Sub

Il faut comprendre que peut importe le nom de la fenêtre fille active, on sait simplement que la fenêtre fille active est dans MIDFilleActive, variable que l'on utilise pour travailler sur cette fenêtre fille.

 

Comment avoir accès aux objets de la fenêtre fille à partir du conteneur?

De la fenêtre conteneur j'ai accès aux objets de la fenêtre fille par l'intermédiaire de la variable MDIFilleActive précédemment mise à jour; par exemple le texte d'un label:

 MDIFilleActive.label1.text

 

Comment avoir accès à des éléments de cette fenêtre fille, une sub Affichetotaux par exemple à partir de ActiveMdiChild:

Si me tape Me.ActiveMdiChild.AfficheTotaux cela plante!!  (car ActiveMdiChild est une instance de la classe Form)

Il faut écrire: CType(ActiveMdiChild, Form2).Affichetotaux() (car il faut convertir ActiveMdiChild en classe Form2)

 

 

Comment parcourir toutes les fenêtres filles?

La collection MdiChildren contient toutes les fenêtres filles, on peut les parcourir:

Dim ff As Form2

For Each ff In Me.MdiChildren

...

Next

Cela est valable s'il n'y a qu'un type de formulaire permettant de créer des formulaires fils (Form2 par exemple)

Mais si on a 2 formulaires Form1 et Form2 cela se complique.

dim i_form as Form ' on utilise une variable Form :formulaire 

dim i_form1 as form1
dim i_form2 as form2

For Each i_form  In Me.mdichildren
    if typeof  i_form is form2 then
        i_form2 = ctype(i_form,form2)
        msgbox i_form2.property_du_form2
    end if

if typeof  i_form is form1 then
        i_form1 = ctype(i_form,form1)
        msgbox i_form2.property_du_form1
    end if

next

Merci Gaël.

Comment fermer toutes le fenêtres filles?

Dim form As Form

For Each form In Me.MdiChildren

form.Close()

Next

 

Comment avoir accès aux objets du conteneur à partir de la fenêtre fille? 

En utilisant Me.MdiParent qui contient le nom du conteneur.

Dans la fenêtre fille le code Me.MdiParent.text ="Document 1" affichera 'Document  1' dans la barre de titre du conteneur.

 

Comment une routine du module conteneur appelle une routine dans la fenêtre fille active?

 Si une routine public de la fenêtre fille se nomme Affiche, on peut l'appeler par:

MDIFilleActive.Affiche()

Il n'est pas possible d'appeler les évènements liés aux objets.

 

Agencement des fenêtres filles :

La propriété LayoutMdi de la fenêtre conteneur modifie l’agencement des fenêtres filles.

0 - MdiLayout.Cascade

1 - MdiLayout.TileHorizontal

2 - MdiLayout.TileVertical

3 - MdiLayout.ArrangeIcons

 

Exemple:

Le menu Item Cascade met les fenêtres filles en cascade.

Protected Sub CascadeWindows_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

   Me.LayoutMdi(System.Windows.Forms.MdiLayout.Cascade)

End Sub

 

A - En VB 2005

 

90% du travail est fait automatiquement: c'est merveilleux!!

Dans l'explorateur de solution: Click droit sur le nom du programme ('mdi' ici):

 

 

Dans le menu, passer par 'Ajouter' puis 'Formulaire Windows':

 

 

Cliquer sur 'MDI Parent Form' ('Formulaire Parent MDI')

On obtient un formulaire MDI parent avec les menus, la barre d'icône, d'état, les menus déroutants avec image:

(Le logiciel a rajouté les 4 outils en bas, nécessaire pour réaliser l'interface.)

 

 

Le code qui génère les formulaires enfants est automatiquement crée:

Public Class MDIParent1

Private Sub ShowNewForm(ByVal sender As Object, ByVal e As EventArgs) Handles NewToolStripMenuItem.Click, NewToolStripButton.Click, NewWindowToolStripMenuItem.Click

' Créer une nouvelle instance du formulaire enfant.

Dim ChildForm As New System.Windows.Forms.Form

' Make it a child of this MDI form before showing it.

ChildForm.MdiParent = Me

m_ChildFormNumber += 1

ChildForm.Text = "Window " & m_ChildFormNumber

ChildForm.Show()

End Sub

Private Sub ExitToolsStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ExitToolStripMenuItem.Click

'Quitter l'application

Global.System.Windows.Forms.Application.Exit()

End Sub

Private Sub CascadeToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles CascadeToolStripMenuItem.Click

'Positionnement des formulaires enfant

Me.LayoutMdi(MdiLayout.Cascade)

End Sub

Private Sub TileVerticleToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles TileVerticalToolStripMenuItem.Click

Me.LayoutMdi(MdiLayout.TileVertical)

End Sub

Private Sub TileHorizontalToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles TileHorizontalToolStripMenuItem.Click

Me.LayoutMdi(MdiLayout.TileHorizontal)

End Sub

Private Sub ArrangeIconsToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ArrangeIconsToolStripMenuItem.Click

Me.LayoutMdi(MdiLayout.ArrangeIcons)

End Sub

Private Sub CloseAllToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles CloseAllToolStripMenuItem.Click

' Ferme tous les formulaires enfant

For Each ChildForm As Form In Me.MdiChildren

ChildForm.Close()

Next

End Sub

Private m_ChildFormNumber As Integer = 0

End Class