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 :

Coordonnées QGraphicsView / QGraphicsScene et ajout d'un item


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 Coordonnées QGraphicsView / QGraphicsScene et ajout d'un item
    Bonjour à vous tous

    Je tente d'ajouter un item (ellipse dans mon cas), sur une scene via un clic de souris. Le soucis étant que quand je clique à un endroit dans ma scene, l'ellipse se forme plus loin (la distance entre mon clic et l'ellipse tracé équivaut à la distance entre l'origine de ma scene et l'origine de mon application.)

    Une petite photo :



    Et mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
        def paintMarkers(self,event):
            self.circleItem = QGraphicsEllipseItem(0.,0.,10.,10.)
            self.circleItem.setPos(self.p.x(), self.p.y())
            self.scene.addItem(self.circleItem)
        def mousePressEvent(self, event):
            self.view.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
            self.p = self.view.mapToScene(event.pos())
            self.paintMarkers(event)
    et mon scene est déclaré ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
           self.scene = QGraphicsScene()
            self.scene.addPixmap(QPixmap.fromImage(im))
            self.view.setCursor(Qt.CrossCursor)
            self.view.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
            self.view.setScene(self.scene)
            self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
            self.view.setDragMode(QGraphicsView.RubberBandDrag)
            self.view.update()
            self.view.fitInView(QRectF(0, 0, w, h), Qt.KeepAspectRatio)
    J'ai essayé toute la journée avec les mapToScene, mapFromScene etc.... Impossible de caler correctement les items à l'endroit ou je clique.
    Je pense qu'il suffirait que je retranche l'origine de ma scene par rapport à mon application, mais je ne sais pas comment trouver les coordonnées de ma scene relative à l'origine de l'application.
    Pour faire quelque chose du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            self.circleItem.setPos(self.p.x()-originerelativescene, self.p.y()-originerelativescene)
    Avez vous une idée de comment faire ça ?

    En vous remerciant par avance,

    Jonathan

  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,

    Ça vient peut-être de l'origine du mousePressEvent.

    Si cette méthode est dans le QGraphicsView alors avec mapToScene tu auras les coordonnées du click dans la scène

    Pour tracer un ligne sur une image à un endroit précis, il me suffit de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        def mousePressEvent(self, event):
            ...
            self.origin_point = self.mapToScene(event.pos())
    Mais le mousePressEvent est celui du QGraphicsView, c'est ça qui importe.

  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
    Merci pour ta réponse,

    Du coup je reviens vers toi. Je me suis dis que le mieux (mais pas le plus simple pour moi) serait de réorganisé mon script.
    Je tente donc de séparer la classe AppWindow (classe principale), de la classe GraphicsView (et d'une troisieme classe SecondWindow qui est une table, fonctionnant parfaitement) :
    Je préviens avant que mon code est surement "sale", j'apprends pyqt de moi même, et malgré mes nombreuses heures de lectures, je n'ai surement pas la même typo que les pros de la programmation

    Code partiel :
    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
     
    import sys
    import win32com.client 
    from PyQt5 import QtCore, QtGui, QtWidgets
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from maingui import Ui_MainWindow
    from tableMessier import Ui_Form
    import re
    from astropy.io import fits
    import array
    from astropy.coordinates import *
    import astropy.units as u
    import numpy as np
    from matplotlib import *
    import threading
    from PIL import Image
    import qimage2ndarray
    from QtImageViewer import QtImageViewer
    import scipy
     
    class AppWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        trigger = pyqtSignal()
     
        def __init__(self):
            super(AppWindow, self).__init__()
            self.setupUi(self)
            self._zoom = 0
     
            self.ccd=None
            #Bouton connect
            self.gotoBtn.clicked.connect(self.coor_goto_clicked)  # Bind the event handlers
            self.quitBtn.clicked.connect(self.close_application)
            self.connectBtn.clicked.connect(self.connect_ascom)
            self.connectBtn.setStyleSheet("background-color: red")
            self.openMessierBtn.clicked.connect(self.open_window)
            self.run_ccdBtn.clicked.connect(self.align_connect)
            self.dialog = SecondWindow(self)
     
            #Initialize the second classe feature
            self.myview = graphicsView(self)
     
        def coor_goto_clicked(self):
            #c = SkyCoord('00 42 30 -41 12 00', unit=(u.hourangle, u.deg))
            rah=self.RaH.text()
            ram=self.RaM.text()
            dech=self.DecH.text()
            decm=self.DecM.text()
            self.c = SkyCoord(rah+':'+ram+' '+dech+':'+decm, unit=(u.hourangle, u.deg))
            self.b=self.c.dec
            self.b=self.b.to_string(decimal=True)
            self.a=self.c.ra.hour
            print("c",self.c.ra,self.c.dec)
            print("cbis",self.b)
            print("a",self.a)
            self.goto()
     
        def goto_thread(self):
            self.connect_ascom()
            self.tel.Tracking = True
            self.tel.SlewToCoordinates(float(self.a), float(self.b))   
            self.update_label()
            self.console.appendPlainText("Goto ok")
     
        def align_connect_thread(self):
            self.trigger.connect(self.align_update)
            self.exp=self.expLine.text()
            self.ccd.StartExposure(self.exp,True)
            wait=True
            while wait:
                if self.ccd.ImageReady:
                    wait = False   
            self.trigger.emit()
     
        def goto(self):
            self.connect_ascom()
            self.console.appendPlainText("Goto en cours...Veuillez patienter")
            thread1=threading.Thread(None,self.goto_thread)
            thread1.start()
     
        def align_connect(self):
            self.connect_ccd()
            self.currentId = 0
            self.maxId = 0
            #self.ccd = win32com.client.Dispatch("ASCOM.Simulator.Camera")
            thread2=threading.Thread(None,self.align_connect_thread)
            thread2.start()
     
     
        def align_update(self):
            global dataimage;
            global im;
            global data;
            global w,we,he
            global h   
            data=np.transpose(self.ccd.ImageArray)
            datax=np.asmatrix(data)
            print("image",np.shape(datax))            
            self.img = Image.fromarray(datax,'L')
            self.img.save('out.png')
            print("image2",np.shape(data))
            im=qimage2ndarray.array2qimage(data)
            h,w=np.shape(data)
            dataimage=QPixmap.fromImage(im)
            hdu = fits.PrimaryHDU(data=data)  
            hdu.scale('float64', option="minmax")
            hdu.writeto('large.fits', clobber=True, checksum=False)
            imq=Image.open('octans2018_min.png')
            he,we,de=np.shape(imq)
            self.he=he
            self.we=we
            self.wecenter=we/2
            self.hecenter=he/2     
            self.myview.update_scene()
     
    class graphicsView (QGraphicsView,Ui_MainWindow):
        def __init__ (self, AppWindow,parent=None):
            super (graphicsView, self).__init__ (parent)
            self._zoom = 0
            self.view=AppWindow.view
            self.scene = QGraphicsScene()
            self.angleSlider=AppWindow.angleSlider
            self.angleSlider.sliderReleased.connect(self.rotate_item) 
            self.setMouseTracking(True)
            self.setInteractive(True)
     
        def mousePressEvent(self, event):
            pos = event.pos()
            item = self.itemAt(pos)
            if item is not None:
                text = 'Rectangle <b>%s</b>' % item.data(0).toString()
            else:
                text = 'No Rectangle (%d, %d)' % (pos.x(), pos.y())
            self.parent().label.setText(text)
            QtGui.QGraphicsView.mousePressEvent(self, event)     
     
        def update_scene(self):
            self.scene.addPixmap(QPixmap.fromImage(im))
            self.view.setCursor(Qt.CrossCursor)
            self.view.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
            self.view.setScene(self.scene)
            self.view.setDragMode(QGraphicsView.RubberBandDrag)
            self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
            self.view.update()
            self.view.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')
            #print("we,he,w,h,w-we,h-he",we,he,w,h,w-we,h-he)
            self.item = self.scene.addPixmap(pixmap)
            posx=(w/2)-(we/2)
            posy=(h/2)-(he/2)
            self.item.setPos(posx,posy)
            self.item.setFlag(QGraphicsItem.ItemIsMovable)
     
        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)
                #if zoom 
            self.scale(zoom, zoom)
            print("view",self.view.scale(zoom, zoom))
     
    class SecondWindow(QtWidgets.QMainWindow,Ui_MainWindow):
        def __init__(self,AppWindow,parent=None):
            super(SecondWindow, self).__init__()
            #self.setupUi(self)
            self.AppWindow=AppWindow
            self.tableWidget = QtWidgets.QTableWidget()
            self.tableWidget.cellClicked.connect(self.cell_was_clicked)
            self.title = 'Catalogue'
            self.setGeometry(50,50,500,500)
     
        def setmydata(self):
            entries=[]
            me_messier=[]
     
    if __name__ == '__main__':
        import sys
        app = QApplication(sys.argv)
        window = AppWindow()
        window.show()
        sys.exit(app.exec_())

    J'ai tenté tout et son contraire, je ne parviens plus à avoir de mouseevent sur ma view/scene, ni même de zoom sur le view (mais je pense que l'ensemble est dû aux events qui ne sont plus reconnus).
    J'en suis à un stade ou je n'arrive plus à avoir du recul sur mon code et notamment sur ce soucis de mouseevent / coordonnées pour ajouter un cercle.

    Quand je lance l'appli, plus de zoom, pas de réponse lors d'un clic sur la view/scene...

    Une idée me ferait un plus grand bien

    Merci par avance,
    Jonathan

  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
    Je ne saisis pas très bien, ta QGraphicsView est censée être physiquement dans ta main window.
    Ici dans ton code elle est virtuellement dans ton appli.
    Ça n'a rien d'anormal qu'elle soit instanciée ailleurs que dans la fenêtre mais il faut l'y placer.

    Je suppose que dans ta fenêtre il y a déjà une QGraphicsView et c'est celle-là que tu vois et non pas self.myview que tu n'as placée nulle part.

    Tes mousePressEvent et wheelEvent devraient être opérationnels.

    Pour mettre ton graphique dans la fenêtre, remplace celui qui est dans Ui_MainWindow par un simple layout. Ensuite, dans ton appli, tu le places dans le layout.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            self.myview = graphicsView(self)
            self.graphic_layout.addWidget(self.myview)
    Dans cette fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        def update_scene(self):
            self.scene.addPixmap(QPixmap.fromImage(im))
    À mon avis tu dois passer l'image en argument (im) non ?

    Et pour ton zoom, tu redimensionnes la pixmap visible, attend-toi à une sérieuse pixelisation de l'image, ça se dégrade assez vite de cette manière.

  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
    Oui je pense que je me suis très mal exprimé, mes excuses.

    Le seul graphicsview que j'ai (et que je veux) est celui de la fenetre principale (voir photo du premier post, qui affiche une image d'étoiles et des ellipses).
    Je pensais qu'en séparant le code et donc en mettant ce graphicsview dans une classe à part pourrait par la suite simplifier les choses niveau lecture de code. J'aurais pas du vu comment je galère à refaire fonctionner mon code. Après je me dis que c'est un mal pour un bien, ça me permettra de mieux saisir mes erreurs.

    Je pensais que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            self.myview = graphicsView(self)
    allait me permettre d'appeler la classe graphicsview et donc de l'initialiser.
    Dans mon ui, j'ai mis un QgraphicsView nommé "view"

    À mon avis tu dois passer l'image en argument (im) non ?
    Hm comment ça ?

    Pour le zoom sur la pixmap c'est voulu, pas de soucis de ce coté, et ça m'allait très bien (quand ça marchait )

  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
    Non, ça n'ira pas, réouvre ta fenêtre dans le Designer et remplace le QGraphicsView par un simple QWidget. (par exemple graphics_widget)
    On appelle cela un placeholder.

    Ensuite dans ton appli
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            self.myview = graphicsView(self)
            layout = QVBoxLayout(self.graphics_widget)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.addWidget(self.myview)
    et, j'avais oublié de le dire, mais enlève absolument la Ui_MainWindow des héritages du QGraphicsView ça va mettre le boxon.

  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
    J'ai mis un Label widget dans l'init de AppWindow ce qui donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            self.view = graphicsView(self)
            layout = QVBoxLayout(self.labelWid)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.addWidget(self.view)
    J'ai remplacé myview par view, car l'ensemble de mon code a ce nom la.
    J'ai aussi enlevé l'héritage Ui_mainwindow.

    Vient alors cette erreur dans def update_scene (class GraphicsView)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     self.view=AppWindow.view
    AttributeError: 'AppWindow' object has no attribute 'view'

  8. #8
    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
    Enlève cette ligne, tu n'en as pas besoin, puisque c'est une référence a l'object QGraphicsView lui-même.

    Et dans cette classe graphicsView tu dois remplacer self.view par self. tout seul puisque self représente la vue.

    Il faut aussi lui rajouter la scène implicitement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            self.scene = QGraphicsScene()
            self.setScene(self.scene)

  9. #9
    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
    Merci beaucoup encore une fois VinsS !! Et merci pour ta pédagogie.
    ça fonctionne très bien désormais ! et mes items se placent au bon endroit !

    Encore un petit soucis de thread, mais je reviendrai une prochaine fois avec un nouveau post si jamais je n'arrive pas à trouver par moi-même !

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

Discussions similaires

  1. ajouter un Jmenu ITem à l'extreme droite
    Par Mo_Poly dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 18/03/2007, 17h46
  2. ajout d'un 'item' à une liste simple
    Par denisvignes dans le forum Access
    Réponses: 8
    Dernier message: 26/09/2006, 15h41
  3. Ajouter dynamiquement un Item à un menu
    Par firejocker dans le forum MFC
    Réponses: 8
    Dernier message: 25/11/2005, 11h52
  4. ajouter dynamiquement des items dans un popup menu
    Par Malone dans le forum Composants VCL
    Réponses: 7
    Dernier message: 23/08/2005, 16h08
  5. Réponses: 2
    Dernier message: 09/05/2003, 17h41

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