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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Par défaut Remonter les informations fournies par l'événement d'un QGraphicsView à une QMainWindow
    Bonjour,

    Ma fenêtre principale contient dans sa zone centrale une instance d'une classe Vue héritant de QGraphicsView et un dock à gauche de la vue.

    Mes figures sont dessinées dans la classe Vue par l'événement réimplémenté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void Vue::mousePressEvent(QMouseEvent *event)
    La figure a dessiné est connue grâce à des actions d'éléments de la barre d'outil de la fenêtre principale. Ces actions envoient un "mode" (polygone, segment, ...) à la vue qui possède une propriété "mode" dont la condition sera traitée dans l'événement mousePressEvent().

    Lorsqu'un QGraphicsItem est alors dessiné à partir de ses points dans mousePressEvent(), les points et l'item sont stockés dans 2 propriétés différentes (QList<>) de ma classe Vue.

    J'aimerais alors pouvoir remonter ces listes de ma Vue à ma fenêtre principale afin de pouvoir afficher mes points et mes items dans le panel de mon dock, le problème étant que ces listes se remplissent au fur et à mesure dans mousePressEvent() et que le QLabel du dock de la fenêtre principale affiche quelque chose de "statique" (pas de rechargement).

    Auriez-vous une idée ?

    Merci

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Bonjour betsprite

    Première réponse, simple : passer par signal/slot :

    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
    View : public QGraphicsView
    {
    Q_OBJECT
    public signals:
       void updateList(List<item>& items);
    ...
    };
     
    MainWindow : public QMainWindow
    {
    Q_OBJECT
    public slots:
       void updateList(List<item>& items);
    ...
    };
     
    MainWindow::MainWindow(...) : QMainWindow(...) ...
    {
       ...
       // create view
       connection(vue, SIGNAL(updateList(List<Item>&)), this, SLOT(updateList(List<Item>&)));
    }
    Ta vue émet simplement un signal qui sera récupéré par la MainWindow (ou autre) et transmettant une référence vers la liste.


    Réponse plus complexe...
    Ma fenêtre principale contient dans sa zone centrale une instance d'une classe Vue héritant de QGraphicsView et un dock à gauche de la vue.
    Ok

    Mes figures sont dessinées dans la classe Vue par l'événement réimplémenté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void Vue::mousePressEvent(QMouseEvent *event)
    Grrr
    Tu dessines ta vue dans un moussePressEvent ! Ce n'est pas le rôle de cette fonction.

    La figure a dessiné est connue grâce à des actions d'éléments de la barre d'outil de la fenêtre principale. Ces actions envoient un "mode" (polygone, segment, ...) à la vue qui possède une propriété "mode" dont la condition sera traitée dans l'événement mousePressEvent().
    Bof
    Ta propriété "mode" est une caractéristique des items, pas de la vue

    Lorsqu'un QGraphicsItem est alors dessiné à partir de ses points dans mousePressEvent(), les points et l'item sont stockés dans 2 propriétés différentes (QList<>) de ma classe Vue.
    Bof et Grrr
    La responsabilité de créer un item ne devrait pas être attribué à QGraphicsView ou dans mousePressEvent(). De plus, ce n'est pas le rôle de la vue de contenir les items (c'est le rôle de la scène).


    Pour résumé, tu as un (gros ?) problème de conception : tu ne respects pas les responsabilités initiales de tes classes ou de tes fonctions (tu les modifies ou tu ajoutes des responsabilités non compatibles).
    Je te conseille de créer 2 classes pour les responsabilités "créer un item" et "contenir les items" et de revoir les responsabilités de chaque classe.
    Je résume sur le schéma suivant les responsabilités des classes et les connections entre elles :



    Bon courage


    PS : Je me permets de te faire ces remarques parce que tu commences à bien connaître Qt. Il te faut maintenant acquérir la "philosophie" Qt
    Images attachées Images attachées  

  3. #3
    Membre éclairé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Par défaut
    Citation Envoyé par gbdivers
    Je me permets de te faire ces remarques parce que tu commences à bien connaître Qt. Il te faut maintenant acquérir la "philosophie" Qt
    Un grand merci vraiment... C'est très gentil de ta part de consacrer du temps à expliquer les choses. Ton schéma aussi est vraiment très bien fait !

    Je comprends mon problème. Je vais reprendre l'architecture de mon application.

    Par contre, je ne dessine pas vraiment mes objets dans l'événement mousePressEvent() mais j'appelle en fonction du mode une méthode de la scène comme "scene->DessinerPolygone()" pour les dessiner.

    Après, c'est vrai que mon gros problème est d'avoir la liste de mes items en propriété dans ma vue. Je vais suivre ton conseil et créer une collection d'items avec une classe pour construire l'item en fonction du mode choisit.

    Enfin, une fois que j'aurais la liste des items, il me sera facile d'envoyer les items ainsi que les points qui leurs sont propres dans ma scène !

    Une question cependant : Dans ma vue, je serais obligé à un moment pour l'affichage d'appeler les méthodes de la classe Scène pour dessiner les items non ? Si oui, à quel endroit dois-je le faire ? Dans des méthodes d'affichage qui appellent les méthodes de dessin de la scène ?

    Merci encore

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Par contre, je ne dessine pas vraiment mes objets dans l'événement mousePressEvent() mais j'appelle en fonction du mode une méthode de la scène comme "scene->DessinerPolygone()" pour les dessiner.
    Ok, c'est mieux

    En fait, il y a 2 manières de mettre à jour le contenu d'un fenêtre :
    - appeler directement la fonction de dessin
    - envoyer un event "update" pour prévenir que la fenêtre doit être mise à jour

    L’inconvénient de la première méthode est que si tu as 1000 modifications du contenu de la fenêtre (par exemple) par seconde, tu auras 1000 tentatives de mise à jour de l'image par seconde, ce qui est inutile (et peut vite devenir lourd à gérer ; fait le test suivant : dessine une ligne qui suit le curseur de la souris par dessus un image en faisant directement la mise à jour de l'affichage : tu auras un effet de scintillement de l'image)

    Le seconde méthode permet au gestionnaire d'events de faire qu'une seule mise à jour du contenu de la fenêtre en "empilant" tous les update event en 1 seul.

    Une question cependant : Dans ma vue, je serais obligé à un moment pour l'affichage d'appeler les méthodes de la classe Scène pour dessiner les items non ? Si oui, à quel endroit dois-je le faire ? Dans des méthodes d'affichage qui appellent les méthodes de dessin de la scène ?
    Ce n'est pas nécessaire. Lorsque tu fais un update de ta vue, elle appelle elle-même la fonction update de la scène (en lui précisant les dimensions du rectangle à afficher, pour ne pas afficher les items qui sont non visible) et la scène renvoi les items à la vue. Mais tout cela est transparent pour l'utilisateur de ces classes

  5. #5
    Membre éclairé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Par défaut
    D'accord ! Merci encore gbdivers

    Je vais déjà essayer de revoir mon code.

    Par contre, j'ai un problème de conception encore : Je dois créer une classe Item (qui hérite de quelque chose ?) pour pouvoir représenter mes items avec en propriété notamment le "mode" pour différencier les figures et ensuite les fournir à la classe CollectionItems...

    J'ai peut être cependant mal compris l'utilisation que tu comptais faire de cette classe ? Si tu dessines les figures dans scène, à quoi servirait une classe Item ?

    Si une telle classe est nécessaire, comment gérer les différents types QGraphicsPolygonItem, QGraphicsLineItem, qui doivent être retourner en pointeur pour être manipuler dans la collection ensuite et qui devraient représenter notre objet Item (instance de la classe Item) ? Car quelque soit l'héritage de la classe Item, on ne pourra pas représenter à partir d'un objet item des sous-classes différentes comme QGraphicsPolygonItem ou QGraphicsLineItem non?

  6. #6
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Bonjour betsprite

    Les items gérés par QGraphics sont obligatoirement des QGraphicsItem (ou dérivés). Donc pour résumé, on a les responsabilité suivantes :
    - QGraphicsScene : contenir de items (des QGraphicsItem)
    - QGraphicsView : afficher des items
    - QGraphicsItem : être contenu dans une scène et être affiché dans une vue (logique)
    Les items sont manipulé dans la scène avec les fonctions addItem(), removeItem() et items() pour respectivement ajouter, supprimer et lister les items.

    La scène étant un conteneur de QGraphicsItem, tu peux ne pas conserver de liste d'items en dehors et utiliser les fonctions précédentes pour les gérer. Par exemple pour ajouter un point dans un polygone :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    QList<QGraphicsItem *> items = scene->items(); // on récupère tous les items
    QGraphicsItem* current_item = find(items.begin(), items.end(), /*critère de sélection*/); // on récupère l'item qui nous intéresse
    QGrapphicsPolygonItem* current_polygon = qobject_cast<QGraphicsPolygonItem*>(current_item); // on cast vers un polygon
    if (current_polygon) // si c'est bien un polygon
    {
       QPolygonF polygon = current_polygon.polygon(); // on récupère la liste des points
       polygon << QPointF(xx, yy); // on ajoute le nouveau point
       current_polygon.setPolygon(polygon); // on met a jour
    }
    On voit que cette méthode est un peu lourde (quel critère de sélection utiliser ?) et n'est pas très POO (bouh le vilain dynamic_cast)

    Plusieurs approches possibles :

    - conserver une liste d'items (c'était mon idée dans le schéma avec la classe ItemCollection). Le problème est qu'on ne supprime pas l’inconvénient de la recherche d'items dans la liste, avec probablement un cast à faire. Donc on peut supprimer cette classe ItemCollection (comme quoi, il est important de prendre le temps d'écrire la conception et de revenir plusieurs fois dessus).

    - Pour éviter le cast, le mieux est de transférer la responsabilité de la gestion des clics directement dans les items (donc dans QGraphicsItem) : les mouse...Event pour sélectionner, déplacer, modifier les items (sur un move event par exemple, on va déplacer un point d'un polygone ou redimensionner un rectangle)
    Il faut alors créer 2 modes : l'ajout d'item (un clic dans la scène = un nouvel item) ou la modification d'item (un clic dans la scène = un nouveau point dans l'item ou modification de l'item). Dans le cas de l'ajout d'item, on crée un nouvel item avec ItemBuilder puis on passe la main à l'item créé.

    - Pour éviter l'étape de recherche des items, le mieux est d'ajouter une variable current_item qui sera mise à jour lors d'un appel à QGraphicsItem::mousePressEvent. On peut par exemple la mettre dans une classe dérivée de QGraphicsScene (avec signal/slot pour communiquer entre l'item et la scène)


    ... la suite bientot, je dois aller chercher du pain

Discussions similaires

  1. Utiliser les informations crées par un programme avec IDle
    Par magalii dans le forum Programmation multimédia/Jeux
    Réponses: 1
    Dernier message: 23/04/2015, 03h01
  2. Réponses: 0
    Dernier message: 10/05/2010, 02h16
  3. Réponses: 2
    Dernier message: 15/09/2009, 14h59
  4. Réponses: 2
    Dernier message: 15/09/2009, 14h59
  5. Réponses: 17
    Dernier message: 16/03/2009, 10h21

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