Bonjour,
je voudrais faire une petite application pour dessiner avec PyQt. J'ai crée un Graphics View auquel j'ajoute une Graphics Scene pour y faire les dessins. Le problème est que ma scène est trop grande. Quand les curseurs sont tout en haut et tout à gauche respectivement, l'application se comporte normalement mais quand on les bouge, cela ne fonctionne plus. Le décalage qui apparaît ne m’étonne pas mais je voudrais savoir comment résoudre ce problème suivant deux méthodes (ma préférence allant à la 1ère):
  1. On ajuste la scène pile au Graphics View.
  2. On fait avec les curseurs variables. Cela doit demander d'utiliser d'autres systèmes de coordonnées pour la souris. Mais lesquelles ?


Par avance merci.


Voici les brouillons des codes.

window_Dessin.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
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
# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'C:\Documents and Settings\Christophe\Mes documents\2,pyBaNaMa\DebuterAvecPythonEtPyQT\CodesProjets\05-Proj5_DessinGraphSouris\03-Dessin\Dessin_v1\window_Dessin.ui     '
#
# Created: Tue Aug 26 19:07:41 2008
#      by: PyQt4 UI code generator 4.4.3
#
# WARNING! All changes made in this file will be lost!
 
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écuopérer foncRetour, la fonction qui sera appellée à partir du GraphicsView personnalisé.
    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
 
    def wheelEvent(self, event):
        self.foncRetour('roulette')
 
    def mouseMoveEvent(self, mouseEvent):
        pt = mouseEvent.pos()
        self.foncRetour('survol',pt.x(),pt.y())
 
    def mousePressEvent(self, mouseEvent):
        if mouseEvent.button() == QtCore.Qt.LeftButton :
            pt = mouseEvent.pos()
            self.foncRetour('simple gauche',pt.x(),pt.y())
        elif mouseEvent.button() == QtCore.Qt.RightButton :
            self.foncRetour('simple droit',mouseEvent.globalX(),mouseEvent.globalY())
 
    def mouseDoubleClickEvent(self, mouseEvent):
        if mouseEvent.button() == QtCore.Qt.LeftButton :
            pt = mouseEvent.pos()
            self.foncRetour('double gauche',pt.x(),pt.y())
        elif mouseEvent.button() == QtCore.Qt.RightButton :
            self.foncRetour('double droit',mouseEvent.globalX(),mouseEvent.globalY())
 
class Ui_window_Dessin(object):
    def setupUi(self, window_Dessin):
        window_Dessin.setObjectName("window_Dessin")
        window_Dessin.resize(697, 538)
        window_Dessin.setMinimumSize(QtCore.QSize(697, 538))
        window_Dessin.setMaximumSize(QtCore.QSize(697, 538))
        self.centralwidget = QtGui.QWidget(window_Dessin)
        self.centralwidget.setObjectName("centralwidget")
        self.layoutWidget = QtGui.QWidget(self.centralwidget)
        self.layoutWidget.setGeometry(QtCore.QRect(9, 9, 681, 481))
        self.layoutWidget.setObjectName("layoutWidget")
        self.horizontalLayout = QtGui.QHBoxLayout(self.layoutWidget)
        self.horizontalLayout.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.graphicsView = GraphicsView_1(self.modifGraph,self.layoutWidget)
        self.graphicsView.setMaximumSize(QtCore.QSize(596, 479))
        self.graphicsView.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.TextAntialiasing)
        self.graphicsView.setObjectName("graphicsView")
        self.horizontalLayout.addWidget(self.graphicsView)
        self.verticalLayout = QtGui.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.bouton_Effacer = QtGui.QPushButton(self.layoutWidget)
        self.bouton_Effacer.setCheckable(False)
        self.bouton_Effacer.setObjectName("bouton_Effacer")
        self.verticalLayout.addWidget(self.bouton_Effacer)
        self.bouton_Point = QtGui.QPushButton(self.layoutWidget)
        self.bouton_Point.setCheckable(True)
        self.bouton_Point.setObjectName("bouton_Point")
        self.verticalLayout.addWidget(self.bouton_Point)
        self.bouton_Segment = QtGui.QPushButton(self.layoutWidget)
        self.bouton_Segment.setCheckable(True)
        self.bouton_Segment.setObjectName("bouton_Segment")
        self.verticalLayout.addWidget(self.bouton_Segment)
        self.bouton_LigneBrisee = QtGui.QPushButton(self.layoutWidget)
        self.bouton_LigneBrisee.setCheckable(True)
        self.bouton_LigneBrisee.setAutoDefault(False)
        self.bouton_LigneBrisee.setDefault(False)
        self.bouton_LigneBrisee.setFlat(False)
        self.bouton_LigneBrisee.setObjectName("bouton_LigneBrisee")
        self.verticalLayout.addWidget(self.bouton_LigneBrisee)
        self.bouton_Cercle = QtGui.QPushButton(self.layoutWidget)
        self.bouton_Cercle.setCheckable(True)
        self.bouton_Cercle.setObjectName("bouton_Cercle")
        self.verticalLayout.addWidget(self.bouton_Cercle)
        self.bouton_zigZag = QtGui.QPushButton(self.layoutWidget)
        self.bouton_zigZag.setCheckable(True)
        self.bouton_zigZag.setObjectName("bouton_zigZag")
        self.verticalLayout.addWidget(self.bouton_zigZag)
        self.horizontalLayout.addLayout(self.verticalLayout)
        window_Dessin.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(window_Dessin)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 697, 21))
        self.menubar.setObjectName("menubar")
        window_Dessin.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(window_Dessin)
        self.statusbar.setObjectName("statusbar")
        window_Dessin.setStatusBar(self.statusbar)
 
        self.retranslateUi(window_Dessin)
        QtCore.QMetaObject.connectSlotsByName(window_Dessin)
 
    def retranslateUi(self, window_Dessin):
        window_Dessin.setWindowTitle(QtGui.QApplication.translate("window_Dessin", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.bouton_Effacer.setText(QtGui.QApplication.translate("window_Dessin", "Effacer", None, QtGui.QApplication.UnicodeUTF8))
        self.bouton_Point.setText(QtGui.QApplication.translate("window_Dessin", "Point", None, QtGui.QApplication.UnicodeUTF8))
        self.bouton_Segment.setText(QtGui.QApplication.translate("window_Dessin", "Segment", None, QtGui.QApplication.UnicodeUTF8))
        self.bouton_LigneBrisee.setText(QtGui.QApplication.translate("window_Dessin", "Ligne Brisée", None, QtGui.QApplication.UnicodeUTF8))
        self.bouton_Cercle.setText(QtGui.QApplication.translate("window_Dessin", "Cercle", None, QtGui.QApplication.UnicodeUTF8))
        self.bouton_zigZag.setText(QtGui.QApplication.translate("window_Dessin", "Zig Zag", None, QtGui.QApplication.UnicodeUTF8))
 
 
if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    window_Dessin = QtGui.QMainWindow()
    ui = Ui_window_Dessin()
    ui.setupUi(window_Dessin)
    window_Dessin.show()
    sys.exit(app.exec_())
TestDesin.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
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# -*- 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 : 26/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,math
from PyQt4 import QtCore, QtGui
# On importe notre boîte de dialogue.
from window_Dessin import Ui_window_Dessin
 
 
# # # # # # # # # # # # # # # # # # # # # #
# Comportement de la boîte de dialogue.   DEBUT
 
class window_Dessin_Plus(QtGui.QMainWindow, Ui_window_Dessin):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        Ui_window_Dessin.__init__(self)
        self.setupUi(self)
 
        self.connect(self.bouton_Point, QtCore.SIGNAL("clicked()"),self.point)
        self.connect(self.bouton_Segment, QtCore.SIGNAL("clicked()"),self.segment)
        self.connect(self.bouton_LigneBrisee, QtCore.SIGNAL("clicked()"),self.ligneBrisee)
        self.connect(self.bouton_Cercle, QtCore.SIGNAL("clicked()"),self.cercle)
        self.connect(self.bouton_zigZag, QtCore.SIGNAL("clicked()"),self.zigZag)
 
# La variable suivante contient les types de dessin faisables à la souris dans le sein de notre application.
# La gestion des attributs graphiques sera juste faitre dans le 5ème projet (on utilisera les calsses présentées au début du tutoriel).
#
# Liste des objets graphiques présentés :
#    selctionner  : ????
#    point  : on doit cliquer le point
#    segment  : on doit cliquer les deux extrémité du segment.  TODO TODO TODO TODO Entre ces deux opérations, nous allons afficher un segment temporaire pour visualiser le segment en cours de construction.
#    cercle  : on doit cliquer le centre puis ensuite un autre point donnant un rayon.  TODO TODO TODO TODO Entre ces deux opérations, nous allons afficher un cercle temporaire pour visualiser le cercle en cours de construction.
#
#Commebtaire sur technique utilisant des constantes globales entières (moins de memoire utilisee)
        self.typeDessin = 'rien'
        self.debutSegment=True
        self.debutLigneBrisee=True
        self.centreCercle=True
        self.debutZigZag=True
        self.coordPtPrecedent=(0,0)
 
 
# Création de la scène où seront fait les dessins.
        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(1,1, 596,479)
        self.graphicsView.setScene(self.scene)
 
    def point(self):
        self.bouton_Segment.setChecked(False)
        self.bouton_LigneBrisee.setChecked(False)
        self.bouton_Cercle.setChecked(False)
        self.bouton_zigZag.setChecked(False)
 
        self.debutSegment=True
        self.debutLigneBrisee=True
        self.centreCercle=True
        self.debutZigZag=True
 
        self.majType()
 
    def segment(self):
        self.bouton_Point.setChecked(False)
        self.bouton_LigneBrisee.setChecked(False)
        self.bouton_Cercle.setChecked(False)
        self.bouton_zigZag.setChecked(False)
 
        self.debutLigneBrisee=True
        self.centreCercle=True
        self.debutZigZag=True
 
        self.majType()
 
    def ligneBrisee(self):
        self.bouton_Point.setChecked(False)
        self.bouton_Segment.setChecked(False)
        self.bouton_Cercle.setChecked(False)
        self.bouton_zigZag.setChecked(False)
 
        self.debutSegment=True
        self.centreCercle=True
        self.debutZigZag=True
 
        self.majType()
 
    def cercle(self):
        self.bouton_Point.setChecked(False)
        self.bouton_Segment.setChecked(False)
        self.bouton_LigneBrisee.setChecked(False)
        self.bouton_zigZag.setChecked(False)
 
        self.debutSegment=True
        self.debutLigneBrisee=True
        self.debutZigZag=True
 
        self.majType()
 
    def zigZag(self):
        self.bouton_Point.setChecked(False)
        self.bouton_Segment.setChecked(False)
        self.bouton_LigneBrisee.setChecked(False)
        self.bouton_Cercle.setChecked(False)
 
        self.debutSegment=True
        self.debutLigneBrisee=True
        self.centreCercle=True
 
        self.majType()
 
 
    def majType(self):
# On trouve la propriété isChecked() en se souvenant des cases à cocher du projet n°2.
        if self.bouton_Point.isChecked() :
            self.typeDessin = 'point'
        elif self.bouton_Segment.isChecked() :
            self.typeDessin = 'segment'
        elif self.bouton_Cercle.isChecked() :
            self.typeDessin = 'cercle'
        elif self.bouton_LigneBrisee.isChecked() :
            self.typeDessin = 'ligne brisee'
        elif self.bouton_zigZag.isChecked() :
            self.typeDessin = 'zig zag'
        else :
            self.typeDessin = 'rien'
 
# En assignant des valeurs aux variables x_souris et y_souris, on les rend optionnelles.
    def modifGraph(self,evenSouris,x_souris=-1,y_souris=-1):
        if evenSouris == 'roulette' :
            self.statusbar.showMessage(u"Graphique - Type <<" + str(self.typeDessin) + u">> - Utilisation de la roulette", 800)
 
        elif evenSouris == 'survol' :
            self.statusbar.showMessage(u"Graphique - Type <<" + str(self.typeDessin) + u">> - Simple survol avec la souris - Le point a pour coordonnées (" + str(x_souris) + ";" + str(y_souris) + u")  relativement au Graphics View", 800)
 
        elif evenSouris == 'simple gauche' :
            self.statusbar.showMessage(u"Graphique - Type <<" + str(self.typeDessin) + u">> - Un clic gauche simple sur le point de coordonnées (" + str(x_souris) + ";" + str(y_souris) + u")  relativement au Graphics View", 0)
 
            if self.typeDessin == 'point' :
                self.nouvPt(x_souris,y_souris)
            if self.typeDessin == 'cercle' :
                self.nouvCercle(x_souris,y_souris)
            if self.typeDessin == 'segment' :
                self.nouvSegment(x_souris,y_souris)
            if self.typeDessin == 'ligne brisee' :
                self.nouvLigne(x_souris,y_souris)
            if self.typeDessin == 'zig zag' :
                self.nouvZigZag(x_souris,y_souris)
 
        elif evenSouris == 'simple droit' :
            self.statusbar.showMessage(u"Graphique - Type <<" + str(self.typeDessin) + u">> - Un clic gauche simple sur le point de coordonnées (" + str(x_souris) + ";" + str(y_souris) + u")  relativement à l'interface globale", 0)
 
        elif evenSouris == 'double gauche' :
            self.statusbar.showMessage(u"Graphique - Type <<" + str(self.typeDessin) + u">> - Un clic gauche double sur le point de coordonnées (" + str(x_souris) + ";" + str(y_souris) + u")  relativement au Graphics View", 0)
 
        elif evenSouris == 'double droit' :
            self.statusbar.showMessage(u"Graphique - Type <<" + str(self.typeDessin) + u">> - Un clic gauche double sur le point de coordonnées (" + str(x_souris) + ";" + str(y_souris) + u")  relativement à l'interface globale", 0)
 
 
# Les méthodes de tracer ont été trouvées dans l'exemple basicdrawing.py des exemples de PyQt (voir le dossier basicdrawing de painting).
# Tout se trouve dans la classe RenderArea de basicdrawing.py.
# La méthode d'ajout des dessins au Graphics View se trouve dans la documentation officielle (voir GraphhicsScene)'exemple pagedesigner.pyw
# du chapitre 12 du livre «*Rapid GUI Programming with Python and Qt*» de Mark SUMMERFIELD.
# La méthode d'ajout des dessins au Graphics View se trouve dans la documentation officielle (voir QGraphhicsScene).
    def nouvPt(self,x_souris,y_souris):
        if self.centreCercle == True :
# Nous allons "simplment" dessiner une croix de centre le point de coorodonnée (x_souris,y_souris).
            pen = QtGui.QPen(QtCore.Qt.SolidLine)
# utilisation du codage RGB des couleurs.
            pen.setColor(QtGui.QColor(0,0,0))
            pen.setWidth(2)
            self.scene.addLine(x_souris - 3, y_souris, x_souris + 3, y_souris, pen)
            self.scene.addLine(x_souris, y_souris-3, x_souris, y_souris + 3, pen)
 
    def nouvSegment(self,x_souris,y_souris):
        pen = QtGui.QPen(QtCore.Qt.SolidLine)
        pen.setColor(QtGui.QColor(255,0,0))
        pen.setWidth(1)
        remplissage=QtGui.QBrush(QtGui.QColor(255,0,0))
 
        if self.debutSegment :
            self.debutSegment = False
            rect=QtCore.QRectF(x_souris - 3, y_souris-3, 6,6)
            self.scene.addRect(rect, pen,remplissage)
            self.coordPtPrecedent=(x_souris,y_souris)
        else :
            self.debutSegment = True
            rect=QtCore.QRectF(x_souris - 3, y_souris-3, 6,6)
            self.scene.addRect(rect, pen,remplissage)
            self.scene.addLine(x_souris, y_souris, self.coordPtPrecedent[0], self.coordPtPrecedent[1], pen)
 
    def nouvLigne(self,x_souris,y_souris):
# Nous allons "simplment" dessiner une croix de centre le point de coorodonnée (x_souris,y_souris).
        pen = QtGui.QPen(QtCore.Qt.SolidLine)
# utilisation du codage RGB des couleurs.
        pen.setColor(QtGui.QColor(100,180,100))
        pen.setWidth(2)
        remplissage=QtGui.QBrush(QtGui.QColor(100,180,100))
 
        rect=QtCore.QRectF(x_souris-3, y_souris-3, 6, 6)
        self.scene.addEllipse (rect, pen, remplissage)
 
        if self.debutLigneBrisee :
            self.debutLigneBrisee=False
        else :
            self.scene.addLine(x_souris, y_souris, self.coordPtPrecedent[0], self.coordPtPrecedent[1], pen)
 
        self.coordPtPrecedent=(x_souris,y_souris)
 
    def nouvCercle(self,x_souris,y_souris):
        pen = QtGui.QPen(QtCore.Qt.SolidLine)
        pen.setColor(QtGui.QColor(50,50,220))
        pen.setWidth(2)
 
        polygon=QtGui.QPolygonF([QtCore.QPointF(x_souris-5,y_souris) , QtCore.QPointF(x_souris,y_souris+5) , QtCore.QPointF(x_souris+5,y_souris) , QtCore.QPointF(x_souris,y_souris-5)])
        self.scene.addPolygon(polygon,pen)
 
        if self.centreCercle :
            self.centreCercle=False
            self.coordPtPrecedent=(x_souris,y_souris)
        else :
            self.centreCercle=True
            rayon=((x_souris - self.coordPtPrecedent[0])**2 + (y_souris - self.coordPtPrecedent[1])**2)**0.5
            rect=QtCore.QRectF(self.coordPtPrecedent[0] - rayon, self.coordPtPrecedent[1]-rayon, 2*rayon,2*rayon)
            self.scene.addEllipse (rect, pen)  # La trioisème variable de remplissage étant optionnelle en ne al mettant pas, aucun relmplissage ne sera fait.
 
    def nouvZigZag(self,x_souris,y_souris):
        pen = QtGui.QPen(QtCore.Qt.SolidLine)
        pen.setColor(QtGui.QColor(255,150,100))
        pen.setWidth(2)
        remplissage=QtGui.QBrush(QtGui.QColor(255,150,100))
 
        rect=QtCore.QRectF(x_souris-2, y_souris-6, 4, 12)
        self.scene.addEllipse (rect, pen, remplissage)
 
        rect=QtCore.QRectF(x_souris-6, y_souris-2, 12, 4)
        self.scene.addEllipse (rect, pen, remplissage)
 
        if self.debutZigZag :
            self.debutZigZag = False
            self.coordPtPrecedent=(x_souris,y_souris)
        else :
            self.debutZigZag = True
# On trace uneligne en Zig zag et non une section de segments enb Zig Zag. Autrement dit, notre Ziga Zag est un seul bloc du point de vue de PyQt ( contrairement à nos lignes brisé
            polygon=QtGui.QPolygonF([QtCore.QPointF(x_souris,y_souris) , QtCore.QPointF(x_souris,y_souris+20) , QtCore.QPointF((x_souris + self.coordPtPrecedent[0])/2,y_souris+20) , QtCore.QPointF((x_souris + self.coordPtPrecedent[0])/2,self.coordPtPrecedent[1]-20) , QtCore.QPointF(self.coordPtPrecedent[0],self.coordPtPrecedent[1]-20) , QtCore.QPointF(self.coordPtPrecedent[0],self.coordPtPrecedent[1])])
            self.scene.addPolygon(polygon,pen,remplissage)
 
# Comportement de la boîte de dialogue.   FIN
# # # # # # # # # # # # # # # # # # # # # # # #
 
 
# # # # # # # # # # # # # # #
# Lancement de l'application.
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    TestSouris = window_Dessin_Plus()
    TestSouris.show()
    sys.exit(app.exec_())