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

wxPython Discussion :

Rafraichissement de sizer lors d'ajout d'un noeud à un arbre


Sujet :

wxPython

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 8
    Par défaut Rafraichissement de sizer lors d'ajout d'un noeud à un arbre
    Bonjour,

    Je me suis mis récemment à python et wxpython, j'ai bidouillé un peu pour manipuler les sizers et fort du succès de mes premiers tests, je me lance dans la réalisation d'un arbre (voir les PJ).
    Le but est de créer un designer "light" de schémas XML, comme avec xmlspy.

    Voilà comment j'ai pensé la chose :
    • chaque noeud et ses descendants définissent une branche de l'arbre
    • chaque branche est définie par un panel qui contient 2 autres panels : un pour le noeud lui-même, un pour les descendants
    • un noeud et ses descendants sont dans un BoxSizer vertical
    • les descendants d'un même noeud (chaque descendant définissant une nouvelle branche) sont positionnés par un BoxSizer horizontal


    J'ajoute mes noeuds dans mon code et j'obtiens ce que vous pouvez voir sur la 1ère pièce jointe (arbre1.png) (les bordures bleu foncé sont autour des branches)
    Jusque là, tout va bien...

    Ensuite, ajout dynamique :
    • Je crée un nouveau panel pour la nouvelle branche, avec les deux panels imbriqués et le sizer vertical.
    • J'ajoute ce panel au sizer horizontal de l'élément parent
    • Dans le premier panel, je crée l'élément window qui définit le noeud (les blocs blancs sur les PJ)
    • Je ne mets rien dans le deuxième panel (normal, l'élément ajouté n'a pas encore d'enfants), mais je définis le sizer horizontal

    Je fais un test, par exemple j'ajoute un élément à la séquence en bas à gauche. Rien ne se passe, ou alors le noeud ajouté apparait partiellement. Si je redimensionne la fenêtre, tout se dessine correctement pour obtenir ce que vous pouvez voir sur la 2nd pièce jointe (arbre2.png).

    Je présume qu'il faut appeler la méthode Layout sur un des sizers, le problème c'est que je ne vois pas lequel. J'ai tenté sur le sizer horizontal dans lequel je viens d'ajouter l'élément, RAS. J'ai tenté sur le vertical associé à la branche, RAS. J'ai tenté un Refresh sur la frame, RAS.
    Faut-il faire un appel à Layout sur tous les sizers de l'arbre (ou au moins de la branche, jusqu'à la racine) ?
    S'il faut faire appel plusieurs fois à Layout, y a-t-il un ordre à respecter dans la hiérarchie des sizers ?
    Faut-il appeler une méthode qui m'est encore inconnue ?

    Merci pour votre attention
    J.
    Images attachées Images attachées   

  2. #2
    Membre éclairé
    Inscrit en
    Septembre 2006
    Messages
    84
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 84
    Par défaut
    Quel refresh tu as tenté?Essaie self.Update() si c'est pas déjà fait. Sinon sympas ta réalisation.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 8
    Par défaut
    Salut Mugen RX,
    J'ai ajouté le Update(), combiné avec Refresh() comme il semble nécessaire d'après la doc, mais sans succès.

    Par ailleurs, en faisant quelques tests, je me suis rendu compte que l'affichage partait en sucette au bout d'un moment (élément wx.Window plus centré et gros paté bleu, éléments ne s'affichant plus et réapparaissant quand j'ajoute plusieurs autres frères)
    Je n'en ai pas identifié la raison mais se pourrait que l'idée de départ soit mauvaise, ou que j'ai oublié certains détails dans sa réalisation.

    (todo : vérifier que ça bugge aussi quand je crée l'arbre directement dans le code )
    [edit] ça bugge aussi au bout d'un moment, mais pas de la même façon (grosse bordure bleue pas du même coté, éléments Window bien centrés). Ça doit venir de l'ordre de création.

    Je vais remettre tout ça au propre en le simplifiant au maximum et éventuellement le poster ici plus tard.

    Sinon sympas ta réalisation.
    merci
    Elle serait encore plus sympa si elle fonctionnait

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 328
    Par défaut
    Salut,

    Je ne connais pas le réponse à ton problème, mais un truc me passait par la tête : Est-ce qu'un wx.TreeCtrl ne conviendrait pas plus à ton projet ?

    A +

  5. #5
    Expert confirmé
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Par défaut
    Comme j'ai eu souvent aussi des soucis de raffraîchissement qui ne se faisait pas (ou plutôt que je n'arriveais pas à faire), je force le rafraichissement d'une fenêtre en rajoutant à ma frame une fonction MyOwnRefresh() qui se contente de redimmensionner la fenêtre d'un pixel puis de la remettre comme avant, ce qui va générer l'évènement OnSize et donc le rafraichissement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def MyOwnRefresh(self):
        size = self.GetSize()
        self.SetSize((size[0]-1, size[1]))
        self.SetSize(size)
    Dès que j'ai besoin de forcer le raffraichissement, j'appelle cette fonction.

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 328
    Par défaut
    Ce peut être également un self.SendSizeEvent() sur ta frame et/ou sur chacun de tes contrôles (alternative à la proposition de Guigui)

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 8
    Par défaut
    Bonsoir et merci pour vos réponses (la mienne est tardive cause coupures internet, veuillez m'en excuser)

    Je vais devoir me contenter de vous dire que pour l'instant, je garde vos réponses sous le coude, car il y a un autre problème en amont.

    J'ai refait mon code pour ne garder que l'essentiel et j'ai testé un affichage non dynamique (j'entends par là que je crée mes composants graphiques directement dans le code), et au bout d'un moment l'affichage n'est plus correct.

    Voici le code :
    Fichier main.pyw
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    # !/usr/bin/python
    # -*- coding:iso-8859-15 -*-
     
    #---------------------------------------------------------------------------
     
    import wx
    import xsd
     
    #---------------------------------------------------------------------------
     
    class TestFrame(wx.Frame):
     
        def __init__(self, title):
            wx.Frame.__init__(self, None, 1, title = title, size = (800, 600), pos = (100, 100))
            self.SetBackgroundColour('#eeeeff')
            # Element racine
            e1 = xsd.Element(self, 'Root')
            # Ajout de noeuds (en cascade)
            [f1, f2, f3, f4, f5] = [e1.addElement() for f in range(5)]
            [g1, g2, g3, g4, g5] = [f1.addElement() for g in range(5)]
            [h1, h2, h3, h4, h5] = [g1.addElement() for h in range(5)]
            # Ajout de noeuds (en profondeur)
            e2 = h2.addElement()
            e3 = e2.addElement()
            e4 = e3.addElement()
            e5 = e4.addElement()
            e6 = e5.addElement()
            e7 = e6.addElement()
            e8 = e7.addElement()
            e9 = e8.addElement()
            # 1er couac
            e10 = e9.addElement()
            # 2ème couac
            e11 = e10.addElement()
     
    #---------------------------------------------------------------------------
     
    class Test(wx.App):
        def OnInit(self):
            print ''
            print '## START ##'
            self._mainFrame = TestFrame('Test')
            self._mainFrame.Show(True)
            self.SetTopWindow(self._mainFrame)
            return True
     
    #---------------------------------------------------------------------------
     
    app = Test(redirect = True, filename = 'stdout.log')
    app.MainLoop()
     
    #---------------------------------------------------------------------------
    Fichier xsd.py
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    # !/usr/bin/python
    # -*- coding:iso-8859-15 -*-
     
    #---------------------------------------------------------------------------
     
    import wx
     
    #---------------------------------------------------------------------------
     
    [
        wxID_XSD_ADD_ELEMENT
    ] = [wx.NewId() for i in range(1)]
     
    #---------------------------------------------------------------------------
     
    # Menu contextuel pour les noeuds de l'arbre
    class XsdContextMenu(wx.Menu):
     
        def __init__(self, parent):
            wx.Menu.__init__(self)
            self._parent = parent
     
            addElement = wx.MenuItem(self, wxID_XSD_ADD_ELEMENT, 'Element')
            self.Bind(wx.EVT_MENU, self.OnAddElement, id = wxID_XSD_ADD_ELEMENT)
            self.AppendItem(addElement)
     
        def OnAddElement(self, event):
            print 'XsdContextMenu::OnAddElement'
            self._parent.addElement()
     
    #---------------------------------------------------------------------------
     
    class Branch(wx.Panel):
     
        n = 0 # un static pour incrémenter le nom du noeud
     
        def __init__(self, parent):
            Branch.n = Branch.n + 1
            wx.Panel.__init__(self, parent, wx.NewId(), name = 'Branch' + str(Branch.n), style = wx.BORDER_NONE)
            self.SetBackgroundColour('#ffeecc') # "saumon"
     
            # conteneur du controle associé au noeud
            self._pnlControl = wx.Panel(self, wx.NewId(), name = 'Branch' + str(Branch.n) + '_PanelControl')
            self._pnlControl.SetBackgroundColour('#ffff00') # jaune
     
            # conteneur des enfants du noeud
            self._pnlChildren = wx.Panel(self, wx.NewId(), name = 'Branch' + str(Branch.n) + '_PanelChildren')
            self._pnlChildren.SetBackgroundColour('#eeeeff') # bleu très clair
     
            # controle associé au noeud
            self._control = self._createControl()
     
            self._bs = wx.BoxSizer(wx.VERTICAL)
            self._bsControl = wx.BoxSizer(wx.VERTICAL)
            self._bsChildren = wx.BoxSizer(wx.HORIZONTAL)
     
            self._bsControl.Add(self._control, 0, wx.ALIGN_CENTRE)
            self._pnlControl.SetSizer(self._bsControl)
            self._pnlChildren.SetSizer(self._bsChildren)
            self._bs.Add(self._pnlControl, 0, wx.EXPAND | wx.ALL, 0)
            self._bs.Add(self._pnlChildren, 1, wx.EXPAND | wx.ALL, 0)
            self.SetSizer(self._bs)
     
        def _createControl(self):
            # A surcharger pour chaque type de noeud concret
            raise NotImplementedError
     
        def addElement(self, label = 'Element'):
            e = Element(self._pnlChildren, label)
            self._bsChildren.Add(e, 0, wx.ALL, 4)
     
            # que faire ici pour rafraichir l'affichage ?
            self._bsChildren.Layout()
            self._bsChildren.Fit(self._pnlChildren)
            self._bs.Layout()
            self.Update()
            return e
     
        def _rightClick(self, event):
            self.PopupMenu(XsdContextMenu(self), (event.GetPosition().x - self.GetScreenPosition().x, event.GetPosition().y - self.GetScreenPosition().y))
            event.StopPropagation()
     
    #---------------------------------------------------------------------------
     
    class Element(Branch):
     
        i = 0
     
        def __init__(self, parent, label = 'Element'):
            Element.i = Element.i + 1
            self._label = label + str(Element.i)
            print 'création de ' + self._label + ' dans ' + parent.GetName()
            Branch.__init__(self, parent)
     
        def _createControl(self):
            win = wx.Panel(self._pnlControl, wx.NewId(), style = wx.BORDER_SIMPLE)
            win.Bind(wx.EVT_CONTEXT_MENU, self._rightClick, id = win.GetId())
            win.SetBackgroundColour('#ffffff')
            bsP = wx.BoxSizer(wx.VERTICAL)
            lbl = wx.StaticText(win, wx.NewId(), label = self._label)
            bsP.Add(lbl, 0, wx.ALIGN_CENTRE | wx.ALL, 4)
            win.SetSizer(bsP)
            return win
     
    #---------------------------------------------------------------------------
    Si vous l'exécutez, vous verrez que Element21 (variable e10) ne s'affixche par correctement (apparition d'une zone de la couleur de fond des branches (#ffeecc, couleur "saumon")) et Element22 (variable e11) n'est pas centré.
    Si vous réduisez la fenêtre pour masquer ces deux éléments (ou faites afficher une autre fenêtre par dessus puis revenez), Element21 semble correct mais la branche de Element22 s'étend de manière inexplicable (pour moi...)

    Je vous avoue que là, je sèche...

    Est-ce qu'un wx.TreeCtrl ne conviendrait pas plus à ton projet ?
    Je trouve les TreeCtrl moins esthétiques pour ce que je veux faire, question d'occupation d'espace et de visibilité pour certains éléments (possibilité de mettre des annotations à coté des noeuds, par exemple). Mais si je ne m'en sors pas avec mon idée actuelle, je serai bien forcé de me tourner vers cette solution, en effet...

    Bonne soirée

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 8
    Par défaut
    Bonjour à toutes et tous,
    J'avais carrément laissé tomber au profit d'un TreeCtrl, mais comme depuis j'ai pas mal appris sur les sizers, j'ai une solution qui me satisfait.

    J'ai abandonné l'imbrication de panels et j'utilise la philosophie suivante :
    • l'arbre est un panel
    • les noeuds sont des BoxSizer verticaux
    • le controle de chaque noeud est un panel+StaticText dont le parent est l'arbre, il est positionné dans le premier SizerItem du noeud
    • les noeuds enfants sont dans un BoxSizer horizontal, lui-même dans le deuxième SizerItem du noeud parent


    Pour le layout, à chaque modification de la structure de l'arbre, il faut appliquer Layout() à chaque sizer impacté. Quand j'ajoute un noeud, je dois faire Layout() sur le sizer horizontal, puis sur le sizer vertical du noeud parent, et remonter ainsi jusqu'au noeud racine.

    Je me suis permis le luxe d'équilibrer les branches selon le nombre de noeuds enfants, en jouant sur la propriété proportion.
    J'ai également dessiné les connecteurs, avec quelques petits soucis d'arrondis (broutille).

    Je mets le code en PJ et je passe en résolu. Si quelqu'un voit des améliorations possibles ou des corrections à apporter, je suis preneur

    Bonne journée
    J.
    Fichiers attachés Fichiers attachés

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

Discussions similaires

  1. Probleme de taille d'un sizer lors de l'ajout d'objets
    Par Skiski dans le forum wxPython
    Réponses: 2
    Dernier message: 28/02/2010, 11h13
  2. Réponses: 2
    Dernier message: 04/12/2007, 18h35
  3. [ToolBar] Problème lors d'ajout/suppression de boutons
    Par joeln3 dans le forum Windows Forms
    Réponses: 5
    Dernier message: 04/09/2007, 15h21
  4. Scroll qui remonte lors de l'ajout d'un noeud au body
    Par Sergejack dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 01/08/2006, 18h11
  5. Réponses: 6
    Dernier message: 19/06/2006, 09h38

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