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 :

[QGraphicsView/Scene] Déplacement de la vue sur la scene via un clic droit


Sujet :

PyQt Python

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2018
    Messages : 17
    Par défaut [QGraphicsView/Scene] Déplacement de la vue sur la scene via un clic droit
    Bonjour bonjour,

    Je vous explique mon problème:

    Le but de la manœuvre est de déplacer la vue d'un QGraphicsView (avec setSceneRect) via un déplacement de souris lors d'un clic droit.
    Comme par exemple, sur adobe reader. Par contre, je ne veux pas que ma scene est une taille finie.
    Sur ma scene se trouve différents QGraphicsProxyWidget déplaçables via un clic gauche + déplacement souris.


    1. J'ai réussi à le faire en réimplémentant les méthodes mousePressEvent, mouseMoveEvent et mouseRealeaseEvent de ma classe héritant de QGraphicsScene.
    Cependant, j'ai besoin pour la suite de mon programme de réimplémenter ces mêmes méthodes dans ma classe héritant de QGraphicsView. (Par exemple pour faire un zoom sur ma scene)
    Lors ce que je fais ça, les trois méthodes réimplémentées de QGraphicsScene ne fonctionne plus.

    Question 1 : Est-ce normal ? Est ce que je fais mal quelques chose ?

    Finalité, je trouve plus logique de gérer toute ma partie interaction graphique via la classe QGraphicsView et ne pas mélanger les deux.

    Voici le code de ma première solution
    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 GraphicsScene(QGraphicsScene):
     
        def __init__(self, parent=None):
            super(GraphicsScene, self).__init__(parent)
     
            self.move_scene_locked = True
            self.move_item_locked = True
            self.item = None
     
        def mousePressEvent(self, event):
            # get the widget if we click on a item
            self.item = self.itemAt(event.scenePos(), QTransform())
     
            if event.button() == Qt.LeftButton:
                # Left click --> Move an item on the scene
                self.move_scene_locked = True
                self.move_item_locked = False
                if self.item is not None:
                    self.setFocusItem(self.item)
                    self.item.item_clicked_from_scene()
     
            elif event.button() == Qt.RightButton:
                # Right click --> Move the view on the scene
                self.move_scene_locked = False
                self.move_item_locked = True
                QApplication.setOverrideCursor(Qt.OpenHandCursor)
     
        def mouseMoveEvent(self, event):
            orig_cursor_position = event.lastScenePos()
            updated_cursor_position = event.scenePos()
     
            # Move an item on the scene
            if self.item is not None and not self.move_item_locked:
                orig_item_position = self.item.scenePos()
                updated_cursor_x = updated_cursor_position.x() - orig_cursor_position.x() + orig_item_position.x()
                updated_cursor_y = updated_cursor_position.y() - orig_cursor_position.y() + orig_item_position.y()
                self.item.setPos(QPointF(updated_cursor_x, updated_cursor_y))
                self.item.item_moved_from_scene(updated_cursor_x, updated_cursor_y)
     
            # Move the view of the scene
            if not self.move_scene_locked:
                QApplication.changeOverrideCursor(Qt.ClosedHandCursor)
                orig_scene_position = self.sceneRect()
                updated_cursor_x = (orig_cursor_position.x() - updated_cursor_position.x())* SPEED_MOVE_FACTOR + orig_scene_position.x()
                updated_cursor_y = (orig_cursor_position.y() - updated_cursor_position.y())* SPEED_MOVE_FACTOR + orig_scene_position.y()
                self.setSceneRect(updated_cursor_x, updated_cursor_y, 500, 500)
     
        def mouseReleaseEvent(self, event):
            self.item = None
            self.move_item_locked = True
            self.move_scene_locked = True
            QApplication.changeOverrideCursor(Qt.ArrowCursor)
    Dans le code ci-dessus, pour calculer et obtenir un déplacement fluide de ma vue, j'utilise la fonction lastScenePos() et scenePos() de QGraphicsSceneEvent qui me permet de calculer le déplacement de ma souris.

    2. Dans ma nouvelle solution, mes fonctions MoveEvent() sont réimplémentées dans ma classe héritant de QGraphicsView. Or dans cette classe, les event sont des QMouseEvent et ils ne possèdent pas de fonction lastPos()...

    Question 2 : Comment vous feriez pour calculer le déplacement de la souris ? Dans le but d'un déplacement fluide. Calculer la différence entre le point où l'on clic et la position de la souris lors du déplacement n'est pas envisageable car plus l'on s'éloigne, plus la View se déplace vite.

    Question 3 : Existe t-il une meilleure solution pour faire un déplacement de caméra avec un clic ?

    Ma problématique n'est pas très simple à expliquer. Dites moi si vous avec besoin de plus d'informations.

    En vous remerciant par avance.
    Alexandre

  2. #2
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Salut,

    Je me demande si tu n'inverses pas la vue et la scene.

    Le rectangle graphique visible dans ton interface est le QGraphicsView, les graphicsItem sont positionnés dans la QGraphicsScene qui peut être plus petite que la vue ou plus grande et, dans ce cas, la vue est une fenêtre que l'on déplace par dessus la scene ou le champ couvert par la camera pour reprendre ta définition.

    Normalement pour déplacer ta scene, donc l'ensemble de ses items, tu ne dois faire que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        self.setDragMode(QGraphicsView.ScrollHandDrag)
    self est le QGraphicsView.

    Evidemment quand on déplace une image dans une fenêtre (plus petite forcément) on a la sensation que l'image glisse sous la fenêtre alors que c'est la fenêtre qui se déplace par-dessus la scene. D'où la confusion.

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2018
    Messages : 17
    Par défaut
    Salut VinsS,

    Je pense avoir bien compris la différence entre la vue et la scene.
    Dans le bout de code que j'ai posté c'est vrai que je manipule la vue depuis la scene. Je travaille maintenant depuis la scene (voir code ci-dessous)

    J'ai essayé d'utiliser "self.setDragMode(QGraphicsView.ScrollHandDrag)" mais je pense que je l'implémente mal parce qu'il ne se passe rien.
    Notamment j'ai essayé d’utiliser self.setDragMode(QGraphicsView.RubberBandDrag) mais ça ne fonctionne pas, je suis donc passé par le widget RubberBandDrag().

    Peux-tu me donner des infos sur son utilisation ?

    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
     
    class PagePowerPlan(QGraphicsView):
     
        def __init__(self, parent=None):
            super(PagePowerPlan, self).__init__(parent)
     
            # Widget for pagePowerPlan
            self.scene = GraphicsScene(self)
            self.scene.setSceneRect(0, 0, 500, 500)
     
            self.setScene(self.scene)
     
            # Variables
            self.list_element_widget = []
            self.list_arrows = []
     
            self.widget_parent = 0
            self.widget_child = 0
            self.index_widget = 0
            self.add_child_parent_connection = False
            self.delete_element = False
     
            # Variables for events
            self.init_mouse_pos = QPoint()
            self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
            self.setDragMode(QGraphicsView.ScrollHandDrag)
     
            self.item = None
            self.move_scene_locked = True
            self.move_item_locked = True
     
            self.delta_mouse_item_pos = None
            self.last_scene = None
     
        def wheelEvent(self, event):
            zoom = event.angleDelta().y()
            if zoom > 0:
                factor = 1.2
            else:
                factor = 0.8
            self.scale(factor, factor)
     
        def mousePressEvent(self, event):
            self.init_mouse_pos = event.pos()
     
            # Select an item
            self.item = self.itemAt(event.pos())
            print(self.item)
     
            # Move an item on the scene
            if event.button() == Qt.LeftButton:
                # Left click --> Move an item on the scene or drag rubber band
                self.move_scene_locked = True
                if self.item is not None:
                    self.move_item_locked = False
                    self.item.item_clicked_from_scene()
                    self.delta_mouse_item_pos = self.item.scenePos() - self.mapToScene(self.init_mouse_pos)
                else:
                    self.move_item_locked = True
                    # Rubber band
                    self.rubber_band.setGeometry(QRect(self.init_mouse_pos, QSize()))
                    self.rubber_band.show()
     
            elif event.button() == Qt.RightButton:
                # Right click --> Move the view on the scene
                self.move_scene_locked = False
                self.move_item_locked = True
                QApplication.setOverrideCursor(Qt.OpenHandCursor)
     
        def mouseMoveEvent(self, event):
            update_mouse_pos = event.pos()
            new_pos_map = self.mapToScene(event.pos())
     
            # Move an item on the scene
            if not self.move_item_locked:
                updated_cursor_x = new_pos_map.x() + self.delta_mouse_item_pos.x()
                updated_cursor_y = new_pos_map.y() + self.delta_mouse_item_pos.y()
                self.item.setPos(QPointF(updated_cursor_x, updated_cursor_y))
                self.item.item_moved_from_scene(updated_cursor_x, updated_cursor_y)
     
            elif self.move_item_locked and self.move_scene_locked:
                self.rubber_band.setGeometry(QRect(self.init_mouse_pos, update_mouse_pos).normalized())
     
            # Move the view of the scene
            if not self.move_scene_locked:
                QApplication.changeOverrideCursor(Qt.ClosedHandCursor)
     
                orig_scene_position = self.sceneRect()
                print(orig_scene_position)
                updated_cursor_x = (update_mouse_pos.x()) + orig_scene_position.x()
                updated_cursor_y = (update_mouse_pos.y()) + orig_scene_position.y()
                self.setSceneRect(updated_cursor_x, updated_cursor_y, 500, 500)
     
        def mouseReleaseEvent(self, event):
            self.item = None
            self.move_item_locked = True
            self.move_scene_locked = True
            QApplication.changeOverrideCursor(Qt.ArrowCursor)
            self.rubber_band.hide()

  4. #4
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Si tu le mets en mode rubberBand tu ne dois pas tracer le cadre toi-même, ça se fait tout seul mais tu auras peut-être besoin de conserver le point de départ parce que le rubberBand disparaît dès qu'on relâche la souris.

    Exemple pour faire un zoom sur un rectangle de sélection:
    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
     
        def mousePressEvent(self, event):
            self.button = event.button()
            mod = event.modifiers()
            if self.button == 1 and self.crop:
                # Outil recadrage, on va tirer un rectangle de sélection
                ...
     
            elif self.button == 1 and (mod == Qt.ControlModifier or self.zoom_area):
                # Zoom avec rectangle de sélection
                self.setDragMode(QGraphicsView.RubberBandDrag)
                # On garde le point de départ
                self.start_pos = self.mapToScene(event.pos())
                self.rubber_band = True
                QGraphicsView.mousePressEvent(self, event)
     
            elif ....
     
            else:
                # Rien à exécuter, on renvoie le signal
                self.setDragMode(QGraphicsView.ScrollHandDrag)
                QGraphicsView.mousePressEvent(self, event)
     
        def mouseMoveEvent(self, event):
            if self.rubber_band:
                # Rien à gérer ici:
                QGraphicsView.mouseMoveEvent(self, event)
     
            elif .....
     
        def mouseReleaseEvent(self, event):
            QGraphicsView.mouseReleaseEvent(self, event)
            self.button = None
            if self.crop:
                # already implemented in cropTool
                self.crop.fix_selection_area()
                event.accept()
     
            elif self.rubber_band:
                self.zoom_selection(self.start_pos, self.mapToScene(event.pos()))
                self.set_zoom_area(False)
     
            self.start_pos = None
            self.rubber_band = False

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2018
    Messages : 17
    Par défaut
    Salut VinsS,

    Merci pour ton retour !
    J'ai essayé ta solution mais rien ne se passe. Je n'ai aucune erreur mais aucune fonctionnalité.
    J'ai l'impression que le setDragMode ne fonctionne pas. Il y a quelque chose d'autre à set pour l'utiliser ?

    Alexandre

Discussions similaires

  1. Plusieurs vues sur un même fichier
    Par minicat dans le forum Eclipse Java
    Réponses: 4
    Dernier message: 05/05/2014, 21h53
  2. Réponses: 4
    Dernier message: 31/10/2005, 16h32
  3. probleme de vue sur sous formulaire
    Par fabrice518 dans le forum Access
    Réponses: 12
    Dernier message: 05/09/2005, 10h35
  4. Déplacement d'une Cible sur une droite
    Par kurul1 dans le forum C++Builder
    Réponses: 10
    Dernier message: 11/07/2005, 16h44
  5. Réponses: 7
    Dernier message: 21/02/2005, 13h28

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