IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

[VB.NET]La bonne gestion des forms [Trucs & Astuces]


Sujet :

Windows Forms

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut [VB.NET]La bonne gestion des forms
    Bonjour !

    Me revoilà avec mes windows forms et leur gestion laborieuse.

    Nous avions déjà vu dans ce post comment gérer l'ouverture et la fermeture des forms correctement (en leur affectant Nothing à la fermeture, et en testant Is Nothing à chaque ouverture).

    J'ai décidé de faire une classe FormControlleur, pour alléger un peu mon code et, dans l'idéal, la réutiliser dans d'autres projets.
    C'est une classe qui émule une dérivation de la collection Forms dans VB6.
    J'ai une Collection (objet Collection, normal) et deux méthodes (en plus d'une méthode New, cela va de soi).
    Mes deux méthodes sont OpenForm et CloseForm.
    Mon algorithme semblait simple : A l'ouverture d'une Form, on regarde si elle est à Nothing. Si c'est le cas, on la crée, on l'affiche. Si ce n'est pas le cas, on "Focus".
    L'algo de fermeture est d'une simplicité déconcertante.

    Maintenant, moi j'ai un problème sur la méthode OpenForm. Je passe ma variable de form par référence, pensant bêtement envoyer un pointeur sur objet.
    - Mes forms sont toutes des instances de classes différentes, alors quelle ligne mettre pour la création d'une form ??
    pi_frmOpen = New (???)

    Ca m'arrangerait vraiment de pouvoir me servir d'une classe pour faier ça, c'est le principe de la programmation orientée objet, non ?... :/

    -Wintermute

  2. #2
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    Citation Envoyé par Wintermute
    Ca m'arrangerait vraiment de pouvoir me servir d'une classe pour faier ça, c'est le principe de la programmation orientée objet, non ?... :/
    C'est effectivemment un des principes de la POO.
    Malheuresement pour l'instanciation, tu dois savoir exactement de quelle type il s'agit. Il faut donc faire un if else pour savoir le type de ta form avant de l'instancier.
    Problème : Si tu as 60 forms différentes c'est pas très beau mais bon.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    sub OpenForm(frm as Form)
        if frm.gettype.equals(Gettype(ClasseForm1)) then
            frm = new ClassForm1
            '......
        elseif  frm.gettype.equals(Gettype(ClasseForm2))  then
            frm = new ClassForm2
            '......
        else
            throw new Exception("Type de form " & frm.gettype.tostring & " non supporté")
        end
    end sub
    Je ne vois pas trop l'interêt de ta classe FormControlleur.
    Pourquoi n'instancie tu pas directement tes classes forms quand l'utilisateur le demande ? i.e si lorqu'il clique sur le bouton A, tu dois instancier la form FormClass1 fais le sur l'evenenement click du bouton.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    Citation Envoyé par abelman
    Je ne vois pas trop l'interêt de ta classe FormControlleur.
    Pourquoi n'instancie tu pas directement tes classes forms quand l'utilisateur le demande ? i.e si lorqu'il clique sur le bouton A, tu dois instancier la form FormClass1 fais le sur l'evenenement click du bouton.
    L'ennui était en fait exposé dans le post vers lequel j'ai redirigé, mais je peux l'exposer à nouveau.
    J'ai une appli MDI, des forms que je fais apparaître par des menus, sous-menus et compagnie. Je voudrais avoir au plus un modèle de chaque form affiché. Si j'instancie bêtement ma form au clic sur un menu, il va y en avoir une nouvelle qui apparaît, or je ne veux pas ce comportement. Si je clique sur le menu correspondant, la form associée passera au premier plan (focus).
    Je voudrais aussi que quand une form est fermée, quand elle réapparaît, elle est toute neuve.
    IL y a une solution : Faire un test à chaque ouverture de form, voir si elle est à Nothing, et auquel cas on la crée. Il faut aussi penser à la passer à Nothing à chaque fermeture. Mais je voudrais un code plus clair, et éviter les redondances à ce niveau-là.

    Autre chose : J'ai déjà essayé un code similaire, mais la fonction GetType ne fonctionne pas sur un objet qui pointe vers Nothing. NulleReference, etc... :/ Je n'ai pas un moyen de passer le type que je veux en paramètre pour le réutiliser ensuite ?

    J'ai 25 Forms, à peu près, ça m'embêterait bien de faire un Select Case de 25 lignes pour "simplifier" mon code et le rendre plus portatif... :/

    -Wintermute, trop exigeant sans doute...

  4. #4
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    Une chose est claire : Tu as 25 forms différentes, donc tu auras 25 appels de "new Form" différents.
    Pour la fonction OpenForm je verrai un truc du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    sub Openform(frm as Form, tp as Type)
        if tp.equals(Gettype(ClasseForm1)) then
            frm = new ClassForm1
            '......
        elseif  tp.equals(Gettype(ClasseForm2))  then
            frm = new ClassForm2
            '......
        else
            throw new Exception("Type de form " & frm.gettype.tostring & " non supporté")
        end 
    end sub
     
    sub CloseForm(frm as Form)
        if not isnothing(frm)
            frm.Close()
        endif
    end sub

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    Mhm, je crois que je vais faire quelque chose comme ça...

    Ca m'amènera deux ennuis majeurs :
    - Si mon appli évolue (elle peut évoluer en mon absence) et que de nouvelles forms font leur apparition, il faudra nécessairement ajouter quelques lignes à cet endroit.

    - Mon module que je voulais portable et réutilisable dans d'autres applis ne le sera qu'à moitié, et c'est un peu dommage... :/

    Je vais sans doute demander l'avis de mes supérieurs. Mais s'il n'y a effectivement aucun moyen de régler ce problème plus simplement...

    J'ai un choix à faire, là. Ou faire un module un peu lourd avec une bonne vingtaine d'appels de case, ou bien je fais du code lourd et redondant, avec des tests identiques à chaque appel...

    Merci pour ton aide. Je le mets pas encore en résolu, quelqu'un aura peut-être une solution, on sait jamais ^^

    [Edit]Pour ceux que ça intéresse, je met le code de ma class FormController. Il n'est pas commenté, mais je doute que ce soit très utile vu sa simplicité. Je passe actuellement le type en chaîne de caractères.
    Cette version est assez générique, je m'en servais comme test. Elle contrôle trois types de forms différents. Pour 25 forms, ce sera pas plus compliqué, juste plus long
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    Public Class FormController
     
    	Shared Sub OpenForm(ByRef pi_frmOpen As Windows.Forms.Form, ByVal pi_sTypeName As String)
     
    		If pi_frmOpen Is Nothing Then
    			Select Case pi_sTypeName
    				Case "frm1"
    					pi_frmOpen = New frm1
    				Case "frm2"
    					pi_frmOpen = New frm2
    				Case "frm3"
    					pi_frmOpen = New frm3
    			End Select
    			pi_frmOpen.Show()
    		End If
    		pi_frmOpen.Focus()
    	End Sub
     
    	Shared Sub CloseForm(ByRef pi_frmClose As Windows.Forms.Form)
     
    		If Not pi_frmClose Is Nothing Then
    			pi_frmClose.Close()
    			pi_frmClose = Nothing
    		End If
    	End Sub
     
    	Shared Sub FocusForm(ByRef pi_frmFocus As Windows.Forms.Form)
     
    		If Not pi_frmFocus Is Nothing Then
    			pi_frmFocus.Focus()
    		End If
     
    	End Sub
     
    End Class
    Voilà voilà ! [/edit]

    -Wintermute, garde espoir !

  6. #6
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    Bon j'ai trouvé une piste pour toi Winter.
    Avec le namespace System.reflection, tu as tous ce qu'il faut pour construire tes formes avec un code générique. Regarde la doc sur system.type.getConstructor

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    imports system.reflection
     
    class form1
    sub new()
    ...
    end sub
    .....
    end class
     
    class form2
    sub new()
    ...
    end sub
    .....
    end class
     
    class FormController
    public shared sub OpenForm(frm as Form, tp as type)
         '......
        dim tps() as type
        dim cinfo as constructorInfo = tp.getconstructor(tps)
        if not is nothing(cinfo) then
             frm = cinfo.invoke(nothing)
        end if
        '.....
    end sub
    end class
     
    'l'appel suivant instanciera un nouvel objet de form1
    dim f as form1
    FormController.OpenForm(f, f.Gettype())
    Ce code devrait marcher si toutes tes forms ont un constructeur sans paramètres. Il se peut qu'il y ai des erreurs car je l'ai pas testé, alors si c'est le cas, refère toi à la doc.
    Mais c'est ce qu'il faut faire

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    Wow, merci beaucoup !
    Bon, je pourrai tester ton algo quand je serai capable de récupérer le type de ma fenêtre.
    Je t'explique le problème : GetType ne renvoie rien tant que ma variable est à Nothing, donc on tourne en rond. Je vais chercher un moyen de récupérer mon type autrement (en le passant directement j'aimerais bien, mais comment ?....)

    Merci encore

    -Wintermute, qui pensait pas que la généricité c'était si laborieux ôO

  8. #8
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    Ah oui excuse moi ..
    C'est la deuxième fois que je l'oublie.
    essaye
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    gettype(form1)    'où form1 est le nom de ta classe. NB : pas besoin de guillemet

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    Bon, je te remercie, j'avais mal compris et je ne connaissais pas cette utilisation de GetType ^^''

    Effectivement ça marche mieux, mais l'algo de la méthode Open semble ne pas fonctionner, je vais essayer de trouver un moyen de palier à ça.

    Voici mon code et où l'erreur intervient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Shared Sub OpenForm(ByRef pi_frmOpen As Windows.Forms.Form, ByVal pi_tpFormType As Type)
    		Dim tps() As Type
    		Dim cinfo As ConstructorInfo = pi_tpFormType.GetConstructor(tps) '<----- Ici erreur
    		If Not cinfo Is Nothing Then
    			pi_frmOpen = cinfo.Invoke(Nothing)
    			pi_frmOpen.Show()
    		End If
    		pi_frmOpen.Focus()
    	End Sub
    Voilà le code de l'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    An unhandled exception of type 'System.ArgumentNullException' occurred in mscorlib.dll
     
    Additional information: Value cannot be null.
    Je vais continuer de chercher dans mon coin avec la doc ! Merci encore

    -Wintermute, assidû

  10. #10
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    lol
    essaie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Dim cinfo As ConstructorInfo = pi_tpFormType.GetConstructor(type.emptytype)

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    Tu m'as pris de vitesse, je venais de l'esssayer
    On va me prendre pour un menteur et un prétentieux

    Bon, effectivement, ça fonctionne, me reste plus qu'à adapter mon code à mon besoin (parce que là on teste plus si la variable est affectée ou non au départ), je poste mon code et on considèrera ça comme résolu !

    Merci encore ! Je m'en serais pas sorti sans toi !

    Voilà comme promis le code de ma classe qui fonctionne à merveille, à présent
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    Imports System.reflection
     
    Public Class FormController
     
    	Shared Sub OpenForm(ByRef pi_frmOpen As Windows.Forms.Form, ByVal pi_tpFormType As Type)
    		Dim cinfo As ConstructorInfo = pi_tpFormType.GetConstructor(Type.EmptyTypes)
    		If Not (cinfo Is Nothing) Then
    			If pi_frmOpen Is Nothing Then
    				pi_frmOpen = cinfo.Invoke(Nothing)
    				pi_frmOpen.Show()
    			End If
    		End If
    		pi_frmOpen.Focus()
    	End Sub
     
    	Shared Sub CloseForm(ByRef pi_frmClose As Windows.Forms.Form)
     
    		If Not pi_frmClose Is Nothing Then
    			pi_frmClose.Close()
    			pi_frmClose = Nothing
    		End If
    	End Sub
     
    	Shared Sub FocusForm(ByRef pi_frmFocus As Windows.Forms.Form)
     
    		If Not pi_frmFocus Is Nothing Then
    			pi_frmFocus.Focus()
    		End If
     
    	End Sub
     
    End Class
    Et voilà un exemple d'appel de la fonction OpenForm :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FormController.OpenForm(monInstance, GetType(MaClasse))
    -Wintermute, winner en retard.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    Allez hop, je re-up, le casse-tête n'est pas terminé, figurez-vous !!

    Je m'explique :
    Essayez d'utiliser ce script dans une application avec des forms MDI, mettons. On aura par exemple une fenêtre qui s'appellera frmMaForm, qui sera une instance de MaClasseDeForm, admettons. Maintenant, corsons un peu les choses.
    Cette fenêtre est une fille MDI d'une autre. Elle a donc deux pointeurs (au moins, peut-être d'autres) qui dirigent vers elle : frmMaForm et (par exemple) frmMDIMère.MDIChildren(1).

    Maintenant, revenons au script en question. Je voudrais, à la fermeture de mon appli, fermer toutes mes fenêtres filles MDI proprement ! Pour ça, je peux faire une boucle dans mes MDIChildren, et utiliser ma méthode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FormController.CloseForm(MDIChildren(i))
    , par exemple. Mais réflechissons un peu... frmMaForm ne sera pas initialisé à Nothing, lui !! Alors il suffit que derrière j'aie un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     FormController.OpenForm(frmMaForm, GetType(MaClasseDeForm))
    Eh bien ça ne passera pas, parce que le test pour voir si MaForm est à Nothing renverra FALSE !

    Mmh, j'aime bien les petits problèmes corsés comme ça ^^

    Alors, j'ai une autre solution : émuler la collection de forms de Visual Basic 6.
    On peut faire une collection qui contiendra des pointeurs vers toutes les fenêtres ouvertes.
    Avant de les ouvrir, on teste qu'elles n'y soient pas déjà.
    En les ouvrant, on ajoute un pointeur à la collection.
    Avant de les fermer, on teste qu'elles y soient bien.
    En les fermant, on retire le pointeur associé à la collection.

    Voilà voilà, j'attends les avis sur ce pseudo-algo, et j'aimerais aussi savoir au possible quel serait le type de collection le plus adapté pour ce genre de travail.

    Merci d'avance et bon courage !

    -Wintermute, qui s'éclate à trouver des failles à ses propres algos ^^

    [Edit]
    Des nouvelles du front ! !
    J'ai réussi à faire quelque chose d'acceptable avec un HashTable, j'utilise le nom de ma Form comme clef. C'est d'ailleurs ce dernier point qui m'ennuie un peu, ça m'empêche de faire deux forms avec un même nom... Quelqu'un connaît un moyen d'obtenir une clef vraiment unique pour un objet ? Une clef que je pourrais retrouver directement ensuite, si possible.

    Merci d'avance !
    -Wintermute, qui est bien content d'avoir fait un an et demi de C++ avant de s'attaquer à VB.NET
    [/Edit]

    [Re-Edit]
    Je m'en sors ! D'ailleurs je crois avoir terminé avec cette classe ^^
    J'utilise donc une collection, au lieu de tester Is Nothing, je vérifie à l'aide d'une jolie boucle While si la form passée en paramètre appartient à ma collection. Si oui, ça veut dire qu'elle est déjà affichée, donc on empêche une nouvelle ouverture, et ainsi de suite.
    C'est beaucoup plus facile et plus logique en fait ! Au lieu de tester le pointeur, on teste l'objet directement

    Voilà voilà, si certains veulent le code source (qui s'est un peu allongé, depuis) n'hésitez pas à me solliciter ici-même

    -Wintermute, victorieux !!
    [/Re-Edit]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Quel SGBD a une bonne gestion des LOGs ?
    Par joker vb dans le forum Décisions SGBD
    Réponses: 12
    Dernier message: 03/04/2008, 17h17
  2. Réponses: 3
    Dernier message: 17/01/2008, 18h11
  3. [asp.net / C# / MySQL] : gestion des droits
    Par leiwulang dans le forum ASP.NET
    Réponses: 6
    Dernier message: 09/01/2008, 21h15
  4. [Vb.Net et C#] Gestion des evenements
    Par hirochirak dans le forum Windows Forms
    Réponses: 4
    Dernier message: 04/04/2007, 15h54
  5. [VB.NET] MainMenu qui ouvre des forms...
    Par Pleymo dans le forum Windows Forms
    Réponses: 26
    Dernier message: 10/10/2005, 15h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo