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 :

Bouger un segment à la souris [QtGui]


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut Bouger un segment à la souris
    Bonjour,
    les codes donnés ci-dessous permettent de créer une fenêtre graphique dans laquelle on peut tracer à la souris des segments ou des lignes brisées (ie un ensemble de segments qui se "suivent"), ainsi que des points isolés et des cercles.

    Le problème est que ma méthode est statique (donc pratiquement inutile) : une fois les objets tracés, impossible de les déplacer. Je voudrais donc savoir comment créer des objets qui peuvent être déplacés. Je pense qu'il faut définir une classe item pour chaque objet graphique, et aussi faire en sorte que les points utilisés par ces items soient "dragables". Les déplacements seront ainsi gérés par PyQt.
    Il faudrait aussi que je sache quand un élément est bougé pour savoir quel objet est bougé.

    Si quelqu'un a une idée je suis preneur.

    LES CODES

    Comportement_GraphicsView.py
    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
    from PyQt4 import QtCore, QtGui
     
    class GraphicsView_1(QtGui.QGraphicsView):
    # Lors du premier appel d'un graphique, on peut lui donner diverses variables mais aussi des fonctions.
    # Nous utilisons cela pour récupérer foncRetour, la fonction qui sera appelée à partir du GraphicsView personnalisé.
    #
    # Cette méthode a été trouvée à l'adresse suivante :
    # http://www.mail-archive.com/pyqt@riverbankcomputing.com/msg13873.html
        def __init__(self, foncRetour, parent=None):
            super(GraphicsView_1, self).__init__(parent)
    # Pour un usage tout au sein de la classe, nous utilisons l'astuce ci-dessous (sans faire cela, nous ne pourrions pas
    # utiliser foncRetour dans n'importe quelle méthode).
            self.foncRetour = foncRetour
     
    # Les différents évènements liés à la souris sont présentés dans le livre «*Rapid GUI Programming with Python and Qt*» de Mark SUMMERFIELD.
        def wheelEvent(self, event):
            print u"Au dessus du graphique 1 : Roulette de la souris activée"
     
        def mouseMoveEvent(self, mouseEvent):
            pt = mouseEvent.pos()
            self.foncRetour(1,pt.x(),pt.y())
     
        def mousePressEvent(self, mouseEvent):
            if mouseEvent.button() == QtCore.Qt.LeftButton :
                pt = mouseEvent.pos()
                print 'Sur le graphique 1 : Clic Gauche avec la souris \nPosition relative (x;y) = (' + str(pt.x()) + ';' + str(pt.y()) + ')'
            elif mouseEvent.button() == QtCore.Qt.RightButton :
                print 'Sur le graphique 1 : Clic Droit avec la souris \nPosition globale (x;y) = (' + str(mouseEvent.globalX()) + ';' + str(mouseEvent.globalY()) + ')'
     
     
    class GraphicsView_2(QtGui.QGraphicsView):
        def __init__(self, foncRetour, parent=None):
            super(GraphicsView_2, self).__init__(parent)
            self.foncRetour = foncRetour
     
        def wheelEvent(self, event):
            print u"Au dessus du graphique 2 : Roulette de la souris activé"
     
        def mouseMoveEvent(self, mouseEvent):
            pt = mouseEvent.pos()
            self.foncRetour(2,pt.x(),pt.y())
     
        def mousePressEvent(self, mouseEvent):
            if mouseEvent.button() == QtCore.Qt.LeftButton :
                pt = mouseEvent.pos()
                print 'Sur le graphique 2 : Clic Gauche avec la souris \nPosition relative (x;y) = (' + str(pt.x()) + ';' + str(pt.y()) + ')'
            elif mouseEvent.button() == QtCore.Qt.RightButton :
                print 'Sur le graphique 2 : Clic Droit avec la souris \nPosition globale (x;y) = (' + str(mouseEvent.globalX()) + ';' + str(mouseEvent.globalY()) + ')'
    window_TestSouris_Plus.py
    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
    # -*- coding: utf-8 -*-
     
    # Form implementation generated from reading ui file 'C:\Documents and Settings\Christophe\Mes documents\2,pyBaNaMa\DebuterAvecPythonEtPyQT\CodesProjets\05-Proj5_DessinGraphSouris\01-TestSouris\window_TestSouris_Plus.ui     '
    #
    # Created: Thu Aug 14 13:49:25 2008
    #      by: PyQt4 UI code generator 4.4.2
    #
    # WARNING! All changes made in this file will be lost!
     
    from PyQt4 import QtCore, QtGui
     
    # On commence par importer les GraphicsView modifiés pour notre usage.
    # Nous pourrions très bien coller ici ces modifications mais que se passerait-il en cas de restrucration visuelle de l'interface ?
    # Nous avons donc choisi de modifier au minimum le code Python de notre interface (toujours dans l'esprit de sépartaion du fond et de la forme).
    from Comportement_GraphicsView import GraphicsView_1, GraphicsView_2
     
    class Ui_window_TestSouris_Plus(object):
        def setupUi(self, window_TestSouris_Plus):
            window_TestSouris_Plus.setObjectName("window_TestSouris_Plus")
            window_TestSouris_Plus.resize(697,538)
            window_TestSouris_Plus.setMinimumSize(QtCore.QSize(697,538))
            window_TestSouris_Plus.setMaximumSize(QtCore.QSize(697,538))
            self.centralwidget = QtGui.QWidget(window_TestSouris_Plus)
            self.centralwidget.setGeometry(QtCore.QRect(0,21,697,498))
            self.centralwidget.setObjectName("centralwidget")
            self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
            self.horizontalLayout.setObjectName("horizontalLayout")
     
    # Voici un autre changement à faire. La ligne originale de window_TestSouris est :
    # self.graphicsView_1 = QtGui.QGraphicsView(self.centralwidget)
            self.graphicsView_1 = GraphicsView_1(self.modifGraph)
    # Ce changement permet d'utiliser notre 1er Graphics View personnalisé en lui fournissant la fonction
    # qu'il utilisera pour indiquer les quelques évènments liés à la souris.
    # Toujours pour réduire au minimum la modification du code Python originel de notre interface,
    # nous définirons plus tard et à part la fonction modifGraph (voir le code de TestSouris_v1).
    # Fin du changement.
     
            self.graphicsView_1.setObjectName("graphicsView_1")
            self.horizontalLayout.addWidget(self.graphicsView_1)
            spacerItem = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Minimum)
            self.horizontalLayout.addItem(spacerItem)
     
    # Même changement que pérécédemment.
            self.graphicsView_2 = GraphicsView_2(self.modifGraph)
    # Fin du changement.
     
            self.graphicsView_2.setObjectName("graphicsView_2")
            self.horizontalLayout.addWidget(self.graphicsView_2)
            window_TestSouris_Plus.setCentralWidget(self.centralwidget)
            self.menubar = QtGui.QMenuBar(window_TestSouris_Plus)
            self.menubar.setGeometry(QtCore.QRect(0,0,697,21))
            self.menubar.setObjectName("menubar")
            window_TestSouris_Plus.setMenuBar(self.menubar)
            self.statusbar = QtGui.QStatusBar(window_TestSouris_Plus)
            self.statusbar.setGeometry(QtCore.QRect(0,519,697,19))
            self.statusbar.setObjectName("statusbar")
            window_TestSouris_Plus.setStatusBar(self.statusbar)
     
            self.retranslateUi(window_TestSouris_Plus)
            QtCore.QMetaObject.connectSlotsByName(window_TestSouris_Plus)
     
        def retranslateUi(self, window_TestSouris_Plus):
            window_TestSouris_Plus.setWindowTitle(QtGui.QApplication.translate("window_TestSouris_Plus", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
     
    if __name__ == "__main__":
        import sys
        app = QtGui.QApplication(sys.argv)
        window_TestSouris_Plus = QtGui.QMainWindow()
        ui = Ui_window_TestSouris_Plus()
        ui.setupUi(window_TestSouris_Plus)
        window_TestSouris_Plus.show()
        sys.exit(app.exec_())
    TestSouris_v1.py
    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
    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
    # Les lignes ci-dessus sont très importantes :
    #	1°) La 1ère ligne indique le codage du fichier Python.
    #	2°) La 2nde ligne est indispensable pour un bon fonctionnement sous Linux.
     
    # PRESENTATION : ce script montre comment lier un  texte ayant un contenu que nous allons analyser
    # à un arbre représentant la struture hiérarchique de ce texte.
    # AUTEUR : BAL Christophe
    # MAIL : projetmbc@club.fr
    # SITE : http://christophe_bal.club.fr/index.php
    # DATE DE CREATION : 14/08/2008
    # 
    # TEST(S) EFFECTUE(S) : programme testé sous Windows XP avec succès.
     
    # On importe les bibliothèques que nous allons utiliser.
    import sys
    from PyQt4 import QtCore, QtGui
    # On importe notre boîte de dialogue.
    from window_TestSouris_Plus import Ui_window_TestSouris_Plus
     
     
    # # # # # # # # # # # # # # # # # # # # # #
    # Comportement de la boîte de dialogue.   DEBUT
     
    class window_TestSouris_Plus(QtGui.QMainWindow, Ui_window_TestSouris_Plus):
    	def __init__(self):
    		QtGui.QMainWindow.__init__(self)
    		Ui_window_TestSouris_Plus.__init__(self)
    		self.setupUi(self)
     
    	def modifGraph(self,num_Graph,x_souris,y_souris):
    		self.statusbar.showMessage(u"Graphique n°" + str(num_Graph) + u" survolé : Souris aux coordonnées (" + str(x_souris) + ";" + str(y_souris) + ")", 500)
     
    # Comportement de la boîte de dialogue.   FIN
    # # # # # # # # # # # # # # # # # # # # # # # #
     
     
    # # # # # # # # # # # # # # #
    # Lancement de l'application.
    if __name__ == "__main__":	
    	app = QtGui.QApplication(sys.argv)
    	TestSouris = window_TestSouris_Plus()
     
    # Affichage d'une boîte de dialogue pour informer l'utilisateur de "l'utilité" de cette 1ère application test.
    # Nous avons déjà rencontré les boîtes de dialogue de PyQt. La seule chose qu'il faille faire c'est d'indiquer
    # que la boîte de dialogue est associé à l'interface TestSouris. Ceci se fait en remplaçant toutes les occurences
    # de self en TestSouris. Ainsi, on doit avoir
    #		QtGui.QMessageBox.information(TestSouris,... 
    # au lieu de
    #		QtGui.QMessageBox.information(self,... 
    # De même, toutes les fonctions
    #		self.tr(...)
    # doivent devenir
    #		TestSouris.tr(...)
    	QtGui.QMessageBox.information(TestSouris, TestSouris.tr(u"Fonctionnement de ce 1er test".encode('ISO-8859-15')),TestSouris.tr(u" En vous baladant sur les deux cadres blancs (qui sont des Graphics View),\n ou en cliquant (droit ou gauche), ou bien en utilisant la roulette,\n vous verrez soit apparaître en bas de la fenêtre, soit dans la console Python  \n des informations relatives à l'action faite et à la position de votre souris.".encode('ISO-8859-15')),QtGui.QMessageBox.Ok)
     
    	TestSouris.show()
    	sys.exit(app.exec_())

  2. #2
    Membre confirmé
    Avatar de doof
    Inscrit en
    Août 2003
    Messages
    160
    Détails du profil
    Informations forums :
    Inscription : Août 2003
    Messages : 160
    Par défaut
    Salut !

    Ma réponse est un peu tardive mais peut-être qu'il n'est pas trop tard.

    Pour pouvoir déplacer tes éléments, le mieux est d'utiliser ce qui est prévu pour dans le "Graphics View Framework" de Qt, à savoir utiliser pour les items des classes dérivées de QGraphicsItem, voir de plus haut niveau (QGraphicsLineItem, QGraphicsEllipseItem...) qui comportent un flag "QGraphicsItem::ItemIsMovable" qu'il suffit de mettre à True, permettant au framework de gérer entièrement les déplacements (et sélections/déplacements multiples en y associant QGraphicsItem::ItemIsSelectable).

    Il faudra donc basculer d'un mode de création d'items que tu gères entièrement à un mode de déplacement/sélection d'items géré par Qt de la façon que tu veux (bouton, appuis sur une touche...). Passer d'un mode à l'autre impliquera juste d'activer ou désactiver les flags ItemIsMovable et ItemIsSelectable de chaque items.

    Le mode de création implique de surcharger les évènements de souris, surtout n'oublie pas de toujours rappeler la méthode de l'évènement pour chaque évènement afin que la propagation d'évènement fonctionne bien et que donc les méthode de déplacement Qt s'accomplissent correctement (je me suis arraché les cheveux à cause de ça ^^).

    Pour savoir quand un élément est bougé et récupérer sa position, c'est faisable dans les évènements mouseReleaseEvent de ta classe d'item par exemple.

    Rien à voir mais j'ai regardé un peu ton code et ta fonction "foncRetour" que tu passe en argument me parait vraiment étrange dans l'esprit Qt ! Pourquoi utilises-tu une fonction de callback alors que tu as un puissant système de signal/slots ? il te suffirait d'émettre un signal passant tes arguments pour effectuer la même chose bien plus proprement.

  3. #3
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Citation Envoyé par doof Voir le message
    Salut !

    Ma réponse est un peu tardive mais peut-être qu'il n'est pas trop tard.
    Mieux vaut tard que jamais... T'inquiètes pas car cela fait quelques mois que je cherche des infos sur ce sujet.

    Citation Envoyé par doof Voir le message
    Rien à voir mais j'ai regardé un peu ton code et ta fonction "foncRetour" que tu passe en argument me parait vraiment étrange dans l'esprit Qt ! Pourquoi utilises-tu une fonction de callback alors que tu as un puissant système de signal/slots ? il te suffirait d'émvaises pratiques en expoliquant pourquettre un signal passant tes arguments pour effectuer la même chose bien plus proprement.
    En fait je suis en train de faire un tuto. sur PyQt qui reprend chronologiquement mon apprentissage y compris les mauvaises idées en expliquant pourquoi le choix est mauvais. Il y aura une partie juste après utilisant les signals/slots personnalisés que je ne connais pas trop au moment je tape ce message.


    Citation Envoyé par doof Voir le message
    Il faudra donc basculer d'un mode de création d'items que tu gères entièrement à un mode de déplacement/sélection d'items géré par Qt de la façon que tu veux (bouton, appuis sur une touche...). Passer d'un mode à l'autre impliquera juste d'activer ou désactiver les flags ItemIsMovable et ItemIsSelectable de chaque items.

    Le mode de création implique de surcharger les évènements de souris, surtout n'oublie pas de toujours rappeler la méthode de l'évènement pour chaque évènement afin que la propagation d'évènement fonctionne bien et que donc les méthode de déplacement Qt s'accomplissent correctement (je me suis arraché les cheveux à cause de ça ^^).
    Pourrais-tu préciser un peu ? As-tu un exemple simple ? Si tu pouvais m’indiquer dans le cas de mon prog. ce qu’il faut faire ce serait très sympa. Mon problème est que tous les exemples que je trouve sur le sujet sont très longs et donc pas faciles à appréhender par un débutant.

  4. #4
    Membre confirmé
    Avatar de doof
    Inscrit en
    Août 2003
    Messages
    160
    Détails du profil
    Informations forums :
    Inscription : Août 2003
    Messages : 160
    Par défaut
    Un code commenté vaut mieux qu'un long discours, je te mets donc un code qui crée dans l'état uniquement des lignes, des rectangles et des ellipses.

    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
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    #!/usr/bin/python
    # -*- coding: utf8 -*-
     
    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
     
    class MainWindow(QMainWindow):
    	def __init__(self):
    		QMainWindow.__init__(self)
    		self.scene = MyGraphicsScene()
    		self.scene.setSceneRect( -500.0, -500.0, 1000.0, 1000.0 );
    		self.view = QGraphicsView()
    		self.view.setScene (self.scene)
    		self.view.setRenderHints(QPainter.Antialiasing)
    		self.setCentralWidget(self.view)
     
    		QObject.connect(self.scene, SIGNAL("modeChanged"), self.changeMode)
     
    	def changeMode(self, mode): # le flag RubberBand pose problème en mode création
    		if mode == 1:
    			self.view.setDragMode(QGraphicsView.NoDrag)
    		else:
    			self.view.setDragMode(QGraphicsView.RubberBandDrag)
     
     
    class MyGraphicsScene(QGraphicsScene):
    	def __init__(self):
    		QGraphicsScene.__init__(self)
    		self.createMode = 0 # 0 = édition, 1 = création
    		self.createState = False # état de la création utile pour l'évènement mouseMoveEvent
    		self.defaultItem = 0 #type d'item à créer
    		self.pen = QPen(Qt.black, 2) # crayon normal d'une figure
    		self.penTemp = QPen(Qt.red, 2) # crayon temporaire à la création
    		self.penOver = QPen(Qt.blue, 2) # crayon quand survolé
     
    	def mousePressEvent(self, e):
    		if e.button() == Qt.LeftButton and self.createMode == 1: # si click gauche en mode création
    			self.firstPoint = e.scenePos() # on prend le premier point en membre de classe
    			self.currentItem = self.createItem() # on crée l'item sans taille
    			self.currentItem.setPen(self.penTemp) # on fixe sa couleur
    			self.addItem(self.currentItem) # on l'ajoute à la scène
    			self.createState = True # on met l'état création en cours à true
    		else:
    			QGraphicsScene.mousePressEvent(self, e)  # on fait suivre l'event
     
    	def mouseReleaseEvent(self, e):
    		if e.button() == Qt.LeftButton and self.createState:# si release gauche en mode création
    			if e.scenePos() == self.firstPoint: # si le point relaché est le même que le premier point
    				self.removeItem(self.currentItem) # on supprime l'item de la scène
    				del self.currentItem # on le supprime même de la mémoire
    			else:
    				self.currentItem.setPen(self.pen) # on lui donne sa couleur normale
    			self.createState = False
    		else:
    			QGraphicsScene.mouseReleaseEvent(self, e) # on fait suivre l'event
     
    	def mouseMoveEvent(self, e):
    		if self.createState: # si on est en cours de création
    			self.currentItem.resize(self.firstPoint, e.scenePos()) # on redimentionne
    		else:
    			QGraphicsScene.mouseMoveEvent(self, e) # on fait suivre l'event
     
    	def keyPressEvent(self, e):
    		key   = e.key()
    		if( key == Qt.Key_Delete): # touche suppr
    			self.removeSelection() # on efface la sélection
    		elif(key == Qt.Key_Space and not e.isAutoRepeat()): # touche espace enfoncée
    			self.swapToCreateMode() # on passe en mode création
    		elif(key == Qt.Key_Return):
    			self.changeDefaultItem() # on change le type d'item à dessiner
     
    	def keyReleaseEvent(self, e):
    		key   = e.key()
    		if(key == Qt.Key_Space and not e.isAutoRepeat()): # touche espace relachée
    			self.swapToEditMode() # on revient en mode edit
     
    	def removeSelection(self): # appelé quand on appuie sur la touche suppr
    		items = self.selectedItems() # on récupère les items sélectionés
    		map(self.removeItem, items) # on les vire de la scène
    		for i in items: # on les détruit totalement
    			del i
     
    	def swapToCreateMode(self):
    		print "Mode creation"
    		self.createMode = 1 # passe en mode création
    		self.emit(SIGNAL("modeChanged"), self.createMode) # emet un signal pour que les items changent de flags
     
    	def swapToEditMode(self):
    		print "Mode edition"
    		self.createMode = 0 # passe en mode édition
    		self.emit(SIGNAL("modeChanged"), self.createMode) # emet un signal pour que les items changent de flags
     
    	def changeDefaultItem(self): # change l'item à creer par défaut
    		self.defaultItem = (self.defaultItem + 1) % 3 # on l'incrémente de 1
    		if self.defaultItem == 0: print "lignes"
    		elif self.defaultItem == 1: print "rectangles"
    		elif self.defaultItem == 2: print "Ellipses"
     
    	def createItem(self): # crée l'item voulu
    		if self.defaultItem == 0: return MyLineItem(self)
    		elif self.defaultItem == 1: return MyRectItem(self)
    		elif self.defaultItem == 2: return MyEllipseItem(self)
     
     
    class VirtualItem(object):
    	def __init__(self):
    		self.setAcceptHoverEvents(False) # flag pour est sensible au survol du curseur
    		self.setFlag(QGraphicsItem.ItemIsMovable, False) # le fameux flag pour le rendre "bougeable"
    		self.setFlag(QGraphicsItem.ItemIsSelectable, False) # flag pour le rendre sélectionnable
     
    		self.Q = QObject() # comme pyQT ne supporte pas l'héritage multiple, seul moyen pour émettre ou recevoir des signaux dans un item
    		self.Q.connect(self.parent, SIGNAL("modeChanged"), self.changeMode) # quand la vue change de mode
     
    	def hoverEnterEvent(self, e):
    		print "Enter", self
    		self.setPen(self.parent.penOver) # couleur de survol
     
    	def hoverLeaveEvent(self, e):
    		print "Leave", self
    		self.setPen(self.parent.pen) # revient à le couleur normale
     
    	def mousePressEvent(self, e):
    		print "Item", self, "pressed at ", self.pos()
    		QGraphicsItem.mousePressEvent(self, e) # on fait suivre l'event
     
    	def mouseReleaseEvent(self, e):
    		print "Item", self, "released at", self.pos()
    		QGraphicsItem.mouseReleaseEvent(self, e) # on fait suivre l'event
     
    	def changeMode(self, mode): #change les flags de l'item suivant le mode création ou édition
    		if mode == 1:
    			self.setAcceptHoverEvents(False)
    			self.setFlag(QGraphicsItem.ItemIsMovable, False)
    			self.setFlag(QGraphicsItem.ItemIsSelectable, False)
    		else:
    			self.setAcceptHoverEvents(True)
    			self.setFlag(QGraphicsItem.ItemIsMovable, True)
    			self.setFlag(QGraphicsItem.ItemIsSelectable, True)
     
     
     
     
     
    class MyLineItem(QGraphicsLineItem, VirtualItem):
    	def __init__(self, parent = None):
    		QGraphicsLineItem.__init__(self)
    		self.parent = parent # une ref sur le parent est utile plus tard (attacher les signaux)
    		VirtualItem.__init__(self)
     
    	def resize(self, p1, p2): # Méthode pour redimensionner l'item
    		self.setLine(QLineF(p1, p2))
     
     
    class MyRectItem(QGraphicsRectItem, VirtualItem):
    	def __init__(self, parent = None):
    		QGraphicsRectItem.__init__(self)
    		self.parent = parent # une ref sur le parent est utile plus tard (attacher les signaux)
    		VirtualItem.__init__(self)
     
    	def resize(self, p1, p2): # Méthode pour redimensionner l'item
    		self.setRect(QRectF(p1, p2))
     
     
    class MyEllipseItem(QGraphicsEllipseItem, VirtualItem):
    	def __init__(self, parent = None):
    		QGraphicsEllipseItem.__init__(self)
    		self.parent = parent # une ref sur le parent est utile plus tard (attacher les signaux)
    		VirtualItem.__init__(self)
     
    	def resize(self, p1, p2): # Méthode poor redimensionner l'item
    		self.setRect(QRectF(p1, p2))
     
     
     
     
     
    if __name__ == "__main__":
    	app = QApplication(sys.argv)
    	window = MainWindow()
    	window.show()
    	sys.exit(app.exec_())

    J'ai commenté toutes les lignes, tu devrais vite comprendre le principe, j'envoie même un signal aux items pour basculer le mode et tu vas voir que c'est vraiment très simple.

    Pour créer un item, il faut donc laisser enfoncée la barre d'espace tout en la dessinant à la souris, quand on relâche la barre d'espace, on rebascule en mode édition, qui permet de sélectionner et déplacer des items. Pour basculer entre création de ligne, de rectangle ou d'ellipse, c'est la touche entré. La touche "suppr" supprime les items séléctionés

    Le principe est simple, je crée une classe qui hérite de QGraphicsScene dans laquelle je surcharge les évenèments de souris pour ma création d'items. pour les Items proprement dis, j'ai créé une classe VirtualItem qui implémente toutes les méthodes communes aux items (surcharge d'évènements souris et basculement de mode). Cette classe ne s'instancie pas toute seule sous peine d'erreurs, en fait chaque item différent est créé par héritage multiple, avec comme parents le QGraphicsItem correspondant et VirtualItem qui évite la redondance de code. Le code dans chaque types d'items implémente les méthodes spécifiques à l'item, comme ici, le redimensionnement.

    Si tu as des questions, n'hésites pas

  5. #5
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Merci pour le code qui est excellent, je n'en demandais pas autant. Avec tes lignes de code non noyées dans un très long listing je devrais comprendre comment cela marche sans aucun problème.
    De plus, j'ai aussi au passage de quoi ajouter une fonctionnalité très utile : l'utilisation du clavier et de la souris pour des fonctionnalités particulières, un vrai bonheur !!!

    Peut-être une dernière petite question ? Sais-tu comment créer un unique objet graphique fabriqué avec plusieurs objets simples. Par exemple, je voudrais très classiquement que les points apparaissent sous forme de croix, il faudrait donc que du point de vue de PyQt, un point soit une réunion de deux segments qui doivent toujours bouger ensemble et non indépendamment l'un de l'autre. J'imagine qu'il faut définir les segments comme enfants du point. Sais-tu faire cela ?

    Encore une fois, merci beaucoup.

  6. #6
    Membre confirmé
    Avatar de doof
    Inscrit en
    Août 2003
    Messages
    160
    Détails du profil
    Informations forums :
    Inscription : Août 2003
    Messages : 160
    Par défaut
    J'ai justement fait ici les items les plus simples, à savoir gérés uniquement par deux points. Si tu veux Dessiner une ligne constituée de "plusieurs lignes", il me semble qu'un QGraphicsPolygonItem doit parfaitement convenir !

    Par contre, c'est un item constitué de plusieurs points, donc la méthode de création va forcément différer. Au lieu d'une séquence "barre d'espace enfoncée, clique gauche, relâche clique gauche", ça pourrait donner "barre d'espace enfoncée, clique, clique, clique, ..., relâche barre d'espace" où chaque clique serait un point. Enfin, c'est à toi de voir et de l'implémenter entièrement avec les évènements de souris.

    Pour ce qui est ensuite de l'édition des points individuels, ça se complique, le but du jeu est donc d'afficher d'autres items "contrôleurs" quand on survole ou sélectionne un item. C'est bien sur faisable mais y'a du boulot, il faut récupérer les coordonnées des points de l'item (facile), et créer temporairement d'autres items spéciaux à ces emplacements précis qui auront uniquement pour but d'envoyer les coordonnées où on les déplaces afin de transformer l'item que l'on édite.

    Tu as normalement à peu près tout ce qu'il te faut sous la main dans mon code plus haut (déplacer des items, modifier leurs coordonnées, connaitre l'item en cours) pour faire ça, après tout dépend de ce que tu veux faire exactement et comment tu comptes l'implémenter, la logique va grandement varier, mais les principes de base restent toujours les mêmes.

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

Discussions similaires

  1. Bouger image avec clavier souris + zoom avec molette
    Par yggdrasylv dans le forum Interfaces Graphiques en Java
    Réponses: 4
    Dernier message: 03/03/2009, 00h02
  2. Bouger le curseur de souris automatiquement
    Par care dans le forum Delphi
    Réponses: 10
    Dernier message: 13/03/2007, 23h04
  3. [c#] ouvrir le menu demarrer et bouger la souris
    Par zedine dans le forum Windows Forms
    Réponses: 4
    Dernier message: 24/02/2006, 18h05
  4. bouger une div selon les coordonnées de la souris
    Par 10-nice dans le forum Général JavaScript
    Réponses: 12
    Dernier message: 21/09/2005, 15h31
  5. Réponses: 2
    Dernier message: 05/07/2005, 17h40

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