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

Discussion :

Dessin droite décalée dans QGraphicsView

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 Dessin droite décalée dans QGraphicsView
    Bonsoir tout le monde,

    J'essaie actuellement de dessiner des droites dans un QGraphicsView qui occupe la zone centrale de ma fenêtre principale. Un stockage des coordonnées des points cliqués par la souris sur la vue est effectué dans une liste ou vector de Points. Une ligne est alors dessinée entre le point de départ, avant dernier clic, et le point d'arrivé, dernier clic.

    Seulement, bien qu'il soit possible de voir les coordonnées des points cliqués en sortie dans QCreator avec l'utilisation de qDebug(), cela ne correspond pas aux points de départ et d'arrivé de la ligne qui est dessinée.

    Autrement dit, si je clique en haut à gauche de ma zone centrale, qDebug() me renvoit "0 : 1" pour x et y et si je clic ensuite en haut à droite, qDebug() donne "1200 : 1", alors que la ligne au final est bien dessinée horizontalement mais au milieu de la zone est pas du tout en haut (screen 1).

    D'ailleurs, si je clique ensuite sur le point de départ de ma ligne dessinée, je n'ai pas "0 : 1" mais environ "2 : 390" ^^, donc en recliquant sur le point de départ de ma ligne, je ne redessinerais pas une ligne confondue à la première mais décalée dans les y (screen 2).

    Voici deux screens présentant ce qui se passe. Pour information, je rappelle que la zone centrale est mon QGraphicsView personnalisé ou Vue, qui est associé à une scène héritant de QGraphicsScene et que ma fenêtre principale a pour dimension 1400 x 800 avec un dock de largeur 200 à gauche.

    Je mets également un zip contenant mon projet pour que vous puissiez tester directement et ainsi mieux comprendre le problème !

    Si vous avez des suggestions n'hésitez pas

    Merci !
    Images attachées Images attachées   
    Fichiers attachés Fichiers attachés

  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

    Le problème provient du fait que la scène corrige automatiquement les coordonnées de la scène à chaque clic. Pour les détails : The Graphics View Coordinate System.

    En résumé : avec graphics view, tu as plusieurs systèmes de coordonnées, en particulier dans la vue et la scène. La correspondance entre la vue et la scène ne donc pas directe : la point (100, 100) de la vue (en coordonnées entières) ne correspond pas forcement au point (100.0, 100.0) de la scène (en coordonnées réelles). Cela dépend du sceneRect : si celui-ci est (0, 0, 1.0, 1.0) et la vue à pour dimensions (800, 800), alors (800, 800) de ta vue correspond au point (1.0, 1.0) dans la scène.

    Par défaut, ce sceneRect n'est pas définit et donc :
    If unset, or if set to a null QRectF, sceneRect() will return the largest bounding rect of all items on the scene since the scene was created (i.e., a rectangle that grows when items are added to or moved in the scene, but never shrinks).
    Le rectangle de transformation est donc recalculé à chaque ajout d'un item (on peut s'en rendre compte très facilement en ajoutant dans Scene:: DessinerDroite() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    qDebug() << sceneRect();
    La solution consiste à définir soi-même ce rectScene avec les mêmes dimensions que la vue en ajoutant dans FenetrePrincipale::FenetrePrincipale() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vue->setSceneRect(QRectF(this->rect()));

    Quelques remarques en vrac :
    - inutile de mettre QWidget::mousePressEvent(event); dans Vue::mousePressEvent() : il est indiqué dans la doc que cette fonction ne fait rien pour QGraphicsView

    - il y a un problème avec tes noms de fichiers : tu mets dans le code des #include avec le nom de fichier en majuscule alors que le nom réel est en minuscule

    - tu as plein de fuite mémoire (new sans delete). D'ailleurs, tu as des new inutiles

    - pourquoi les classes Point, Polygon et Segment alors que tu as des classes Qt qui font la même chose ?

    - utilises QGraphicsPolygonItem et QGraphicsPathItem pour dessiner plusieurs lignes connectés plutôt que de créer plusieurs QGraphicsLineItem

    - c'est pas cool les fenêtres à taille fixe


    Bon courage

  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
    avec graphics view, tu as plusieurs systèmes de coordonnées, en particulier dans la vue et la scène.
    Ok je comprends mieux le problème !

    Citation Envoyé par gbdivers
    La solution consiste à définir soi-même ce rectScene avec les mêmes dimensions que la vue en ajoutant dans FenetrePrincipale::FenetrePrincipale()
    En effet, les dimensions étant maintenant similaires, le problème est résolu ! merci

    Citation Envoyé par gbdivers
    Quelques remarques en vrac :
    - inutile de mettre QWidget::mousePressEvent(event); dans Vue::mousePressEvent() : il est indiqué dans la doc que cette fonction ne fait rien pour QGraphicsView Ok pour ce point !

    - il y a un problème avec tes noms de fichiers : tu mets dans le code des #include avec le nom de fichier en majuscule alors que le nom réel est en minuscule En effet, merci

    - tu as plein de fuite mémoire (new sans delete). D'ailleurs, tu as des new inutiles Ici, je suppose que tu fais allusion à mes objets QGraphicsView, QGraphicsScene, QGraphicsLineItem et mon objet vector qui devraient être détruits à la fermeture de l'application ?
    Mais comment utiliser dans des classes personnalisées les destructeurs des classes mères ? (plus une question de C++ et POO je sais :p)


    - pourquoi les classes Point, Polygon et Segment alors que tu as des classes Qt qui font la même chose ? Ici, je pensais ne pas utiliser QPolygon ou QPoint pour utiliser toutes les classes QGraphics comme QGraphicsPolygon et QGraphicsItem en les redéfinissant par héritage pour une "harmonie" avec ma QGraphicsScene et QGraphicsView mais il est vrai que QPoint pourrait tout de même être utilisé pour remplacer Point. QPolygon en revanche ne peut pas remplacer complétement ma classe Polygone non ? car elle hérite de QGraphicsPolygonItem pour être bien intégré dans ma QGraphicsView. Qu'en penses-tu ?

    - utilises QGraphicsPolygonItem et QGraphicsPathItem pour dessiner plusieurs lignes connectés plutôt que de créer plusieurs QGraphicsLineItem Complétement d'accord. Pour l'instant, ce n'est qu'un test. Par contre, j'utiliserai bien QGraphicsPolygonItem pour faire des polygones et QGraphicsLineItem pour un et un seul segment

    - c'est pas cool les fenêtres à taille fixe Pas faux
    Merci !

  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
    - tu as plein de fuite mémoire (new sans delete). D'ailleurs, tu as des new inutiles
    Ici, je suppose que tu fais allusion à mes objets QGraphicsView, QGraphicsScene, QGraphicsLineItem et mon objet vector qui devraient être détruits à la fermeture de l'application ?
    Mais comment utiliser dans des classes personnalisées les destructeurs des classes mères ? (plus une question de C++ et POO je sais :p)
    Non. Ces objets sont détruit automatiquement par la scène lors de sa destruction.

    Je parle des new que tu utilises sans delete. Par exemple, dans Vue::mousePressEvent(), tu as :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // vector<Point> ListePoints;
    Point *p = new Point(PosX, PosY);
    ListePoints.push_back(*p);
    tu crées donc un objet dans le tas puis tu copies dans un vecteur l'objet (et non le pointeur). Tu as donc 2 objets "Point" en mémoire : celui créé par new et celui créé lors de la copie (push_back).

    Plusieurs solutions :
    - soit tu détruis ton objet après la copie dans le vecteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // vector<Point> ListePoints;
    Point *p = new Point(PosX, PosY);
    ListePoints.push_back(*p);
    delete p;
    - soit tu ne le crées pas dans le tas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // vector<Point> ListePoints;
    Point p(PosX, PosY);
    ListePoints.push_back(p);
    C'est la méthode la plus simple que je choisirais dans ce cas

    - soit tu crées un vecteur de pointeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // vector<Point*> ListePoints;
    Point *p = new Point(PosX, PosY);
    ListePoints.push_back(p);
    dans ce cas, il ne faut pas oublier de détruire les points dans le destructeur (avec qDeleteAll ou std::for_each + delete) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Vue::~Vue()
    {
        qDeleteAll(ListePoints);
    }
    Cette solution sera intéressante uniquement si l'objet créer est de taille conséquente et que la copie coûte chère. On préfère dans ce cas créer un objet dans le tas et copier simplement le pointeur.
    Dans le cas d'un point, contenant juste 2 doubles, le coût n'est pas important (surtout qu'il n'y pas de nombreuses opérations de copies) donc on peut utiliser la copie de l'objet directement.


    - pourquoi les classes Point, Polygon et Segment alors que tu as des classes Qt qui font la même chose ?
    Ici, je pensais ne pas utiliser QPolygon ou QPoint pour utiliser toutes les classes QGraphics comme QGraphicsPolygon et QGraphicsItem en les redéfinissant par héritage pour une "harmonie" avec ma QGraphicsScene et QGraphicsView mais il est vrai que QPoint pourrait tout de même être utilisé pour remplacer Point. QPolygon en revanche ne peut pas remplacer complétement ma classe Polygone non ? car elle hérite de QGraphicsPolygonItem pour être bien intégré dans ma QGraphicsView. Qu'en penses-tu ?
    Attention, ne confond pas les différents types de classes : QPointF, QLinesF et QPolygonF sont de simples conteneurs, QGraphicsLineItem et QGraphicsPolygonItem sont des "items" au sens du framework Graphics View (donc contenus dans une scène, affichable dans une vue, sur lesquels on peut utiliser QTransform, QAnimation, etc.). Donc, c'est bien les items que tu veux manipuler.

    La question est de savoir s'il est nécessaire de dériver ces classes, c'est à dire est ce que tu souhaites modifier leurs comportements par défaut. Si tes items ne font rien de plus que se dessiner, alors c'est leurs comportements par défaut et il n'est pas nécessaire de les dériver.
    Tu devrais dériver par exemple si tu souhaites que l'on puisse cliquer sur une ligne et qu'elle devient en gras avec des ancres sur les extrémités pour la modifier.
    Dans le cas où le comportement par défaut suffit, tu n'as pas à dériver 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
    Citation Envoyé par gbdivers
    Je parle des new que tu utilises sans delete[...]
    Ok je vois le problème. Je pense que je vais utiliser la solution la plus simple bien que la solution du vecteur de pointeurs paraît en effet intéressante.

    Citation Envoyé par gbdivers
    Attention, ne confond pas les différents types de classes : QPointF, QLinesF et QPolygonF sont de simples conteneurs, QGraphicsLineItem et QGraphicsPolygonItem sont des "items" au sens du framework Graphics View (donc contenus dans une scène, affichable dans une vue, sur lesquels on peut utiliser QTransform, QAnimation, etc.). Donc, c'est bien les items que tu veux manipuler.
    Voila la signification du terme "harmonie" que j'avais utilisé à défaut d'explication claire comme celle-ci :p

    Citation Envoyé par gbdivers
    Si tes items ne font rien de plus que se dessiner, alors c'est leurs comportements par défaut et il n'est pas nécessaire de les dériver.
    Oui c'est tout à fait logique ! En fait, je préfère partir en héritant à chaque fois mes classes pour prévoir une éventuelle modification future sur mon objet qui ne pourrait être permise avec la classe mère.

    Merci pour tout gbdivers pour tes explications claires et très justes

  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
    En fait, je préfère partir en héritant à chaque fois mes classes pour prévoir une éventuelle modification future sur mon objet qui ne pourrait être permise avec la classe mère.
    En effet, se compliquer la vie est une solution
    Sinon tu peux utiliser un simple typedef par défaut et ne créer les classes que lorsque tu en as besoin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef QGraphicsLineItem LineItem;
    typedef QGraphicsPolygonItem PolygonItem;

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

Discussions similaires

  1. Comment dessiner une ligne dans un Chart ?
    Par libititi dans le forum Composants VCL
    Réponses: 3
    Dernier message: 16/06/2005, 14h56
  2. [ALGO] dessiner un triangle dans le bon sens
    Par lefait dans le forum Algorithmes et structures de données
    Réponses: 13
    Dernier message: 05/02/2005, 14h38
  3. dessiner un tableau dans WORD?
    Par sali dans le forum VBA Word
    Réponses: 2
    Dernier message: 26/01/2005, 14h11
  4. Dessiner une ligne dans un cube transparent ?
    Par Muetdhiver dans le forum OpenGL
    Réponses: 4
    Dernier message: 04/05/2004, 11h06
  5. [PaintBox] Persistance du dessin non créé dans onPaint
    Par princesse dans le forum C++Builder
    Réponses: 10
    Dernier message: 21/04/2004, 17h47

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