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

Qt Discussion :

Conflit entre itemIsMovable et mouseReleaseEvent [Graphics View]


Sujet :

Qt

  1. #1
    Invité
    Invité(e)
    Par défaut Conflit entre itemIsMovable et mouseReleaseEvent
    Bonjour.

    Pour la question, prière de compiler le code (très simplifié) ci-dessous.
    Pourquoi mon objet rect (classe RectItem) revient-il dans sa position initiale à partir du deuxième déplacement à la souris ? Essayez de le bouger plusieurs fois et vous comprendrez. Ce comportement étrange survient lorsque j'implémente mouseReleaseEvent. Avez-vous une solution qui me permette d'implémenter cette méthode tout en conservant le flag ItemIsMovable ? Merci.

    Le code :
    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
    #include <QApplication>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QGraphicsRectItem>
    #include <QGraphicsSceneMouseEvent>
    #include <QDebug>
     
     
    // QGraphicsView subclass
    class GraphicsView : public QGraphicsView {
    public:
        GraphicsView(QGraphicsScene *scene) : QGraphicsView(scene) {}
    };
     
    // QGraphicsRectItem subclass
    class RectItem : public QGraphicsRectItem {
    public:
        RectItem(int x, int y, int width, int height) : QGraphicsRectItem(x, y, width, height) {}
        void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
    };
     
    // mouse events on RectItem items: make drag&drop bug! (see flag ItemIsMovable)
    void RectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
        qDebug() << "released mouse";
        event->accept();
    }
     
     
    int main(int argc, char *argv[]) {
     
        QApplication app(argc, argv);
     
        // test drag&drop with flag ItemIsMovable
        QGraphicsScene scene(0, 0, 400, 300);
     
        RectItem *rect = new RectItem(100, 100, 40, 40);
        rect->setBrush(QColor(Qt::blue));
        rect->setPen(Qt::NoPen);
        rect->setFlag(rect->ItemIsMovable, true);
        scene.addItem(rect);
     
        GraphicsView view(&scene);
        view.setBackgroundBrush(QColor(255, 255, 200));
        view.show();
     
        return app.exec();
    }

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Salut,

    Sans avoir compilé, je dirais que c'est parce que tu accepte l'événement, mais que tu ne redéfinis pas la nouvelle position de ton objet

    La méthode accept d'un événement indique juste que l'on s'attendait à ce que l'événement survienne à ce moment là, et qu'on le juge donc valide, mais cela ne fait rien d'autre

    Dans le cas présent, tu dis "juste" que, oui, l'utilisateur avait raison de relâcher le bouton de la souris, mais il manque le principal : le fait de déplacer effectivement ton objet à la position indiquée par la souris

    Ton code devrait donc ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void RectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
        qDebug() << "released mouse";
        setPos(event->scenePos());
        /* ou peut etre bien quelque chose comme 
        QPointf pos = event->scenePos();
        QRectf rect(pos.x(), pos.y(),rect().width(),rect().height());
        setRect(rect);
        car je ne sais plus de tete si la première version gardera le rectangle
        non modifiée :P */
        event->accept();
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    En fait, je te dois une petite explication...

    Le flag "ItemIsMovable" indique uniquement que, si ton objet fait partie d'une sélection et que tu déplace la souris dans un mouvement de drag (bouton gauche enfoncé), ton objet suivra les mouvements de la souris pour t'indiquer la position qu'il pourrait prendre.

    Mais ce flag n'implique absolument pas le fait que, au moment où tu vas relâcher la souris, la position de ton objet soit modifiée pour prendre la position indiquée par ta souris, et c'est normal...:

    Imagine un peu que tu aies trois rectangles à des endroits différents qui soient sélectionnés.

    Ces trois rectangles ont, bien évidemment les mêmes dimensions, sinon, ce ne serait pas marrant, hein

    Si le fait de relâcher la souris modifiait la position des trois rectangles, ils se retrouveraient tous les trois superposés.

    Cela ne te conviendrait certainement pas parce que tu te serais sans doute attendu à ce que celui sur lequel était ta souris prenne la position indiquée par la souris et que les deux autres prenne une position relative identique à celle qu'ils avaient avant d'être déplacés (le premier en haut à gauche du deuxième et le troisième en bas à droit du deuxième, le tout à des distances de X, Y entre le premier et le deuxième et de X' et Y' entre le deuxième et le troisième, si c'étaient leurs positions d'origines )

    Et puis, il y a tous les problèmes liés à l'imprécision de la souris...

    Mettons que tu aies divisé ta scène en dix zones horizontales, représentées par 9 lignes et que ton rectangle doive, pour une raison qui ne tient qu'à toi, être positionné exactement à équidistance des deux lignes entre lesquelles il se trouve.

    Ton rectangle réagira au déplacement de la souris qu'elle se trouve près du coin supérieur gauche, au centre ou près du coin inférieur droit de ton rectangle (en fait : quelle que soit la position de ta souris sur la surface de ton rectangle )

    Quand tu vas relacher le bouton de la souris, tu peux le faire sur toute la distance qui sépare les deux lignes.

    Si tu te contentes de prendre la position de la souris et de considérer que cette position est celle du coin supérieur gauche de ton rectangle, il y a 9 chances sur 10 que ton rectangle ne sera pas correctement positionné, et les chances seront encore moindre si tu considère qu'il faut poser le rectangle exactement là où il apparait (en effectuant donc le calcul de la position réelle du coin supérieur gauche par rapport à la position relative de la souris au moment où l'on a cliqué )

    Dans les deux cas, il t'appartiendra de récupérer la position de la souris et d'en déduire, d'une manière ou d'une autre, la position effective que doit (doivent) prendre l'élément (les éléments) sélectionnés

    Comme tu le vois, il est tout à fait impossible de définir le moindre comportement de déplacement par défaut de manière sereine.

    C'est la raison pour laquelle, quand l'événement se produit, le comportement par défaut est uniquement... de signaler que l'événement est accepté, et qu'il est donc temps de remettre la vue à jour

    Le fait d'invoquer la fonction accept() de ton événement va uniquement placer un flag à true pour indiquer de, effectivement, ton objet s'attendait bel et bien à ce que tu finisses par lâcher le bouton de la souris, mais rien d'autre... Et surtout pas aller modifier tes données, ni les propriétés des objets de ta vue, simplement parce que ce n'est pas le rôle d'un événement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Invité
    Invité(e)
    Par défaut
    Merci pour tes réponses.

    En ajoutant la ligne setPos(event->scenePos()); dans la méthode mouseReleaseEvent, le bug se produit toujours. Je te conseille vraiment de compiler le code pour t'en rendre compte.

    De plus, sans implémenter aucune méthode de gestion d'événement (ni press, release, ni doubleclick, rien), le flag ItemIsMovable se suffit à lui-même : l'objet rect est bien déplacé et ne retourne pas dans sa position initiale quand on essaie de le déplacer à nouveau.

    En outre, l'implémentation de la seule méthode mousePressEvent ne produit pas du tout ce mauvais comportement : je peux gérer l'événement comme bon me semble (même laisser la méthode vide !), le rectangle se déplacera effectivement et correctement.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Je n'ai pas résolu ce bug mystérieux du conflit en le flag ItemIsMovable et la méthode mouseReleaseEvent.

    En tout cas j'ai trouvé le moyen d'opérer une sorte de drag&drop (pas au sens Qt avec les types MIME, mais juste le déplacement du rectangle via la souris), sans passer par ce flag maudit :

    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
    #include <QApplication>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QGraphicsRectItem>
    #include <QGraphicsSceneMouseEvent>
    #include <QPoint>
    #include <QDebug>
     
     
    // QGraphicsView subclass
    class GraphicsView : public QGraphicsView {
    public:
        GraphicsView(QGraphicsScene *scene) : QGraphicsView(scene) {}
    };
     
    // QGraphicsRectItem subclass
    class RectItem : public QGraphicsRectItem {
    public:
        RectItem(int x, int y, int width, int height) : QGraphicsRectItem(x, y, width, height) {
            setCursor(Qt::OpenHandCursor);
        }
        void mousePressEvent(QGraphicsSceneMouseEvent *event);
        void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
        void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
     
    protected:
        QPoint mousePressPt;
    };
     
    // mouse events on RectItem items
    void RectItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
        qDebug() << "pressed mouse";
     
        setCursor(Qt::ClosedHandCursor);
     
        mousePressPt.setX(pos().x() - event->scenePos().x());
        mousePressPt.setY(pos().y() - event->scenePos().y());
    }
    void RectItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
        setX(mousePressPt.x() + event->scenePos().x());
        setY(mousePressPt.y() + event->scenePos().y());
     
        event->accept();
    }
    void RectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
        qDebug() << "released mouse";
     
        setCursor(Qt::OpenHandCursor);
     
        setX(mousePressPt.x() + event->scenePos().x());
        setY(mousePressPt.y() + event->scenePos().y());
     
        event->accept();
    }
     
     
    int main(int argc, char *argv[]) {
     
        QApplication app(argc, argv);
     
        // test drag&drop with flag ItemIsMovable
        QGraphicsScene scene(0, 0, 400, 300);
     
        RectItem *rect = new RectItem(100, 100, 40, 40);
        rect->setBrush(QColor(Qt::blue));
        rect->setPen(Qt::NoPen);
        scene.addItem(rect);
     
        GraphicsView view(&scene);
        view.setBackgroundBrush(QColor(255, 255, 200));
        view.show();
     
        return app.exec();
    }

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

Discussions similaires

  1. Conflit entre javascript et script ASP
    Par Mvu dans le forum ASP
    Réponses: 2
    Dernier message: 22/02/2005, 17h28
  2. Possibles conflits entre GL, GLAUX et GLUT
    Par barthelv dans le forum GLUT
    Réponses: 1
    Dernier message: 19/11/2004, 13h31
  3. Conflit entre bases de données
    Par BRODU dans le forum Bases de données
    Réponses: 4
    Dernier message: 18/10/2004, 12h40
  4. conflit entre couleurs
    Par khayyam90 dans le forum OpenGL
    Réponses: 2
    Dernier message: 03/07/2004, 19h00
  5. [Technique] Conflits entre plusieurs requêtes
    Par Neowile dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 24/03/2003, 10h37

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