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

PyQt Python Discussion :

[PyQT] MouseEvent , déplacer et peindre


Sujet :

PyQt Python

  1. #1
    Membre du Club
    Inscrit en
    Mai 2011
    Messages
    72
    Détails du profil
    Informations forums :
    Inscription : Mai 2011
    Messages : 72
    Points : 49
    Points
    49
    Par défaut [PyQT] MouseEvent , déplacer et peindre
    Bonjour à vous tous,

    J'ai un GraphicScene défini dans une classe GraphicsView :

    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
     
    class graphicsView (QGraphicsView):
        def __init__ (self, AppWindow,parent=None):
            super (graphicsView, self).__init__ (parent)
            self._zoom = 0
            #self.parent = parent       
            #self.scene=AppWindow.scene
            self.scene = QGraphicsScene()
            self.angleSlider=AppWindow.angleSlider
            self.angleSlider.sliderReleased.connect(self.rotate_item)
            self.setMouseTracking(True)
            self.setInteractive(True)
            self.coo1line=AppWindow.coo1line
            self.coo2line=AppWindow.coo2line
            self.coo3line=AppWindow.coo3line
            self.setMouseTracking(True)
     
    def hoverEnterEvent(self, event):
        shape = QtGui.QCursor(QtCore.Qt.CrossCursor)
        cursor = QtGui.QCursor(shape, -1, -1)
        self.setCursor(cursor)
     
    def wheelEvent(self, event):
        self.zoom_step = 1.1
        zoom_in = event.angleDelta()    
        if zoom_in.y() > 0:
            zoom = self.zoom_step  
        else:
            zoom = 1 / self.zoom_step
            print("zoom",zoom)
        self.scale(zoom, zoom)
        print("view",self.scale(zoom, zoom))
     
    def paintMarkers(self, event):
        self.circleItem = QGraphicsEllipseItem(0,0,10,10)
        self.circleItem.setPos(self.p.x()-self.circleItem.boundingRect().width()/2.0,
                               self.p.y()-self.circleItem.boundingRect().height()/2.0)
        self.scene.addItem(self.circleItem)
        self.circleItem.setPen(QtGui.QPen(QtCore.Qt.red, 1.5))
     
    def mousePressEvent(self, event):
        super(graphicsView, self).mousePressEvent(event)
        self.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
        self.p = self.mapToScene(event.pos())
        self.paintMarkers(event)
        #self.item.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y())
     
    def mouseMoveEvent(self, event):
        super(graphicsView, self).mouseMoveEvent(event)
        self.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
     
    def mouseReleaseEvent(self, event):
        super(graphicsView, self).mouseReleaseEvent(event)
        self.leftClick = False
    Dans cette scène, j'affiche une première image, puis une seconde que j'aimerai déplacer à la souris.

    J'aimerai aussi pouvoir rajouter des items (ellipse) en cliquant sur la scène (quand je clique pas sur la seconde image). J'arrive à faire marcher soit l'un soit l'autre.

    Quand je supprime "def paintMarkers" ainsi que son appel dans MousePressEvent, je parviens à faire bouger ma seconde image. Par contre quand il est activé, je parviens à faire des petites ellipses mais je ne peux plus déplacer la seconde image.

    J'ai essayé de voir du coté de itemAt, pour que lorsque qu'on clique sur la seconde image on puisse la déplacer, mais je ne parviens pas du tout à le faire fonctionner.

    Auriez vous des astuces pour faire fonctionner les deux modes en même temps ?

    Merci par avance à tout ceux qui m'aideront !

  2. #2
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Qt est un framework conçu pour que tout soit sous-classable, ce qui confère une grande facilité de gestion des élément affichés. Y compris les widgets qui peuvent ainsi acquérir une certaine indépendance par rapport au programme principal. Par exemple une boîte d'outils peut faire une remise à zéro de ses paramètres dans un certain contexte sans que le programme principale ne lui dise ce qu'il faut faire.

    Il en va de même avec les objets graphiques. Il est plus aisé de les sous-classer et de réimplémenter leurs interactions avec la souris.

    Tout en sachant qu'un même code peut servir pour plusieurs objets.

    Montre l'exemple avec la deuxième image déplaçable à la souris.

  3. #3
    Membre du Club
    Inscrit en
    Mai 2011
    Messages
    72
    Détails du profil
    Informations forums :
    Inscription : Mai 2011
    Messages : 72
    Points : 49
    Points
    49
    Par défaut
    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
    class graphicsView (QGraphicsView):
        def __init__ (self, AppWindow,parent=None):
            super (graphicsView, self).__init__ (parent)
            self._zoom = 0
            #self.parent = parent        
            #self.scene=AppWindow.scene
            self.scene = QGraphicsScene()
            self.angleSlider=AppWindow.angleSlider
            self.angleSlider.sliderReleased.connect(self.rotate_item) 
            self.setMouseTracking(True)
            self.setInteractive(True)
            self.coo1line=AppWindow.coo1line
            self.coo2line=AppWindow.coo2line
            self.coo3line=AppWindow.coo3line
            self.setMouseTracking(True)
     
        def rotate_item(self):
            angle = self.angleSlider.value()
            print(angle)
            transform = QtGui.QTransform()
            centerX = self.item.boundingRect().width()/2
            centerY = self.item.boundingRect().height()/2
            transform.translate( centerX , centerY  )
            transform.rotate( -angle )
            transform.translate( -centerX , -centerY )
            self.item.setTransform( transform )
     
        def hoverEnterEvent(self, event): 
            shape = QtGui.QCursor(QtCore.Qt.CrossCursor)
            cursor = QtGui.QCursor(shape, -1, -1) 
            self.setCursor(cursor)
     
        def wheelEvent(self, event):
            self.zoom_step = 1.1
            zoom_in = event.angleDelta()     
            if zoom_in.y() > 0:
                zoom = self.zoom_step   
            else:
                zoom = 1 / self.zoom_step
                print("zoom",zoom)
            self.scale(zoom, zoom)
            print("view",self.scale(zoom, zoom))
     
        def mousePressEvent(self, event):
            super(graphicsView, self).mousePressEvent(event)
            self.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
            self.p = self.mapToScene(event.pos())
     
        def mouseMoveEvent(self, event):
            self.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor)) 
     
        def mouseReleaseEvent(self, event):
            self.leftClick = False
    Ce code me permet d'avoir la deuxième image qui peut se déplacer avec la souris. J'imagine que par défaut l'image on-top peut etre déplacer si mousePressEvent est déclarée.
    La différence avec le premier code du premier post est l'ajout de la fonction paintMarkers, qui lui ajouter le fait de dessiner des ellipses, mais qui du coup supprime le fait de pouvoir deplacer l'item pixmap lors d'un click de souris (item pixmap = image secondaire, c'est à dire sur mon image les petits cercles bleus cyan qui sont un même .png).


  4. #4
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Elle n'apparaît nulle part dans ton code cette deuxième image.

    Où et comment est-elle créée ? C'est le cercle bleu ?

  5. #5
    Membre du Club
    Inscrit en
    Mai 2011
    Messages
    72
    Détails du profil
    Informations forums :
    Inscription : Mai 2011
    Messages : 72
    Points : 49
    Points
    49
    Par défaut
    Elle apparait ici (octans2018_min.png), dans une fonction de cette meme classe GraphicsView. Ce sont les petits cercles bleus cyan, pas le gros cercle bleu. Les petites ellipses dessinées dans cette update_scene sont les cercles rouges.


    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
        def update_scene(self):
            self.scene.addPixmap(QPixmap.fromImage(im))
            self.setCursor(Qt.CrossCursor)
            self.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
            self.setScene(self.scene)
            self.setDragMode(QGraphicsView.RubberBandDrag)
            self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
            self.update()
            self.fitInView(QRectF(0, 0, w, h), Qt.KeepAspectRatio)
            elw=w/2
            elh=h/2
            painter = QPainter(self)
            pen = QtGui.QPen(Qt.red, 1)
            self.scene.addEllipse(elw-(20/2), elh-(20/2), 20, 20,pen)
            self.scene.addEllipse(elw-(200/2), elh-(200/2), 200, 200,pen)
            self.scene.addEllipse(elw-(h/2), elh-(h/2), h, h,pen)
            self.scene.addLine(0,h/2,w,h/2,pen)
            self.scene.addLine(w/2,h,w/2,0,pen)
            pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.green))
            brush = QtGui.QBrush(pen.color().darker(150))
            pixmap = QPixmap('octans2018_min.png')
            self.item = self.scene.addPixmap(pixmap)
            posx=(w/2)-(we/2)
            posy=(h/2)-(he/2)
            self.item.setPos(posx,posy)

  6. #6
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    En plus tu en as plusieurs de ces items.

    Alors le plus simple sera ceci:
    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
     
            self.item = OctantItem(self)
            self.scene.addItem(self.item)
            posx=(w/2)-(we/2)
            posy=(h/2)-(he/2)
            self.item.setPos(posx,posy)
     
     
    class OctantItem(QGraphicsPixmapItem):
        def __init__(self, ui):
            super().__init__()
            self.ui = ui
            self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable | 
                            QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges |
                            QtWidgets.QGraphicsItem.ItemIsFocusable)
            self.setAcceptHoverEvents(True)
            pix = QPixmap('octans2018_min.png')
            self.setPixmap(pix)
     
        def hoverEnterEvent(self, event):
            self.setCursor(Qt.CrossCursor)
            event.accept()
     
        def hoverLeaveEvent(self, event):
            self.setCursor(old cursor)
            event.accept()
     
        def mousePressEvent(self, event):
            # memoriser la position actuelle
            self.current_pos = event.scenePos()
     
        def mouseMoveEvent(self, event):
            pos = event.scenePos()
            new_x, new_y = pos.x(), pos.y()
            delta_x = self.current_pos.x() - new_x
            delta_y = self.current_pos.y() - new_y
            self.moveBy(delta_x, delta_y)
            self.current_pos = pos
    Je le fais de mémoire, donc à corriger probablement.
    Si ton item doit signaler son déplacement, tu peux soit utiliser self.ui.octant_moved()soit utiliser un pyqtSignal mais dans les deux cas j'ajouterais un index à mon item pour savoir lequel a envoyé le signal.

    Pour un effet de survol plus visuel, tu peux réduire l'opacité de l'item self.setOpacity(0.8) et remettre l'opacité à 1 dans la méthode hoverEnterEvent.

    Une question, pourquoi utilises-tu une image pour un simple cercle ?

  7. #7
    Membre du Club
    Inscrit en
    Mai 2011
    Messages
    72
    Détails du profil
    Informations forums :
    Inscription : Mai 2011
    Messages : 72
    Points : 49
    Points
    49
    Par défaut
    Je me répète une nouvelle fois...merci VinsS ça fonctionne ! et du coup ça me donne pas mal d'idées.

    J'ai multiplié delta_x et delta_y par -1 afin d'avoir le déplacement dans le sens du déplacement de la souris, et pas à l'opposé :
    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
    class OctantItem(QGraphicsPixmapItem):
        def __init__(self, ui):
            super().__init__()
            self.ui = ui
            self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable | 
                            QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges |
                            QtWidgets.QGraphicsItem.ItemIsFocusable)
            self.setAcceptHoverEvents(True)
            pix = QPixmap('octans2018_min.png')
            self.setPixmap(pix)
     
        def hoverEnterEvent(self, event):
            self.setCursor(Qt.CrossCursor)
            self.setOpacity(0.5)
            event.accept()
     
        def hoverLeaveEvent(self, event):
            self.setCursor(Qt.CrossCursor)
            self.setOpacity(1.)
            event.accept()
     
        def mousePressEvent(self, event):
            # memoriser la position actuelle
            self.current_pos = event.scenePos()
     
        def mouseMoveEvent(self, event):
            pos = event.scenePos()
            new_x, new_y = pos.x(), pos.y()
            delta_x = self.current_pos.x() - new_x
            delta_y = self.current_pos.y() - new_y
            self.moveBy(delta_x*-1, delta_y*-1)
            self.current_pos = pos
    Concernant l'image, il y a en fait une petite dizaine de cercles bleus cyan, qui doivent se déplacer ensemble suivant une distance bien précise par rapport au centre de cette image. J'ai pensé que ça serait bien plus simple de réaliser une image avec un pattern bien tracé, et que je déplacerai l'ensemble...

    J'ai juste encore un petit soucis, quand je déplace l'image, j'ai une ellipse rouge qui est tracée lors du clic (qui vient de MousePressEvent de la classe précédente et de la fonction PaintMarkers) Il y a possibilité de la désactiver cette fonction lorsque je déplace l'image et ainsi autoriser le tracage d'ellipse rouge uniquement lorsque je ne suis pas sur l'image qui peut bouger?

Discussions similaires

  1. déplacer un élément d'une table
    Par Sph@x dans le forum Requêtes
    Réponses: 3
    Dernier message: 10/02/2004, 12h12
  2. déplacer un fichier
    Par bourinator dans le forum C
    Réponses: 9
    Dernier message: 24/09/2003, 20h29
  3. Réponses: 5
    Dernier message: 24/04/2003, 22h08
  4. Déplacer la sélection d'une ligne dans un stringgrid
    Par jer64 dans le forum Composants VCL
    Réponses: 5
    Dernier message: 14/03/2003, 00h57
  5. TChart : déplacer un point
    Par Nicolas dans le forum C++Builder
    Réponses: 3
    Dernier message: 06/11/2002, 18h05

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