2017-09-02 13 views
1

Je suis en train de créer une application PyQt qui est censée recevoir des clics avec le bouton droit de la souris sur un QGraphicsView, dessiner un "lasso" (une ligne qui s'étend de l'origine cercle à la position de la souris), puis, à la libération de la souris, effacez les graphiques lasso et affichez une boîte de dialogue de saisie pour la partie suivante de l'application.Artefact du menu Qt lors de l'appel de la boîte de dialogue

Pour une raison quelconque, lorsque j'utilise la souris pour cliquer sur "Ok" dans la boîte de dialogue de saisie, un artefact de menu apparaît sur QGraphicsView qui contenait le lasso. L'artefact de menu est une ligne de menu déroulant qui indique "(coche) Exit". Parfois, il peut aussi s'agir du menu contextuel d'un de mes QGraphicsObjects personnalisés - mais pour une raison quelconque, l'appel de la boîte de dialogue puis un clic sur "Ok" provoquent un événement indésirable de type clic droit sur QGraphicsView. Cela ne semble se produire que lorsque la dernière étape avant le retour de la méthode est le QInputDialog - le remplacer par un passage ou un appel à une autre méthode n'aboutit pas à l'artefact. Je serais très reconnaissant à quiconque avec une idée de ce qui cause ce problème!

Voici le code minimal:

import sys 
from PyQt4 import QtCore, QtGui 

class Window(QtGui.QMainWindow): 
    # The app main window. 

    def __init__(self): 
     super(Window, self).__init__() 

     # Initialize window UI 
     self.initUI() 


    def initUI(self, labelText=None): 
     # Set user-interface attributes. 

     # Set up menu-, tool-, status-bars and add associated actions. 
     self.toolbar = self.addToolBar('Exit') 

     # Create a menu item to exit the app. 
     exitAction = QtGui.QAction(QtGui.QIcon('icons/exit.png'), '&Exit', self) 
     exitAction.triggered.connect(QtGui.qApp.quit) 
     self.toolbar.addAction(exitAction) 

     # Create the main view. 
     self.viewNetwork = NetworkPortal() 
     self.viewNetwork.setMinimumWidth(800) 
     self.viewNetwork.setMinimumHeight(800) 

     self.setCentralWidget(self.viewNetwork) 
     self.show() 


class NetworkPortal(QtGui.QGraphicsView): 
    # A view which allows you to see and manipulate a network of nodes. 

    def __init__(self): 
     super(NetworkPortal, self).__init__(QtGui.QGraphicsScene()) 

     # Add the CircleThing graphic to the scene. 
     circleThing = CircleThing() 
     self.scene().addItem(circleThing) 


class CircleThing(QtGui.QGraphicsEllipseItem): 
    # Defines the graphical object. 

    def __init__(self): 
     super(CircleThing, self).__init__(-10, -10, 20, 20) 

     # Set flags for the graphical object. 
     self.setFlags(
         QtGui.QGraphicsItem.ItemIsSelectable | 
         QtGui.QGraphicsItem.ItemIsMovable | 
         QtGui.QGraphicsItem.ItemSendsScenePositionChanges 
        ) 

     self.dragLine = None 
     self.dragCircle = None 

    def mouseMoveEvent(self, event): 
     # Reimplements mouseMoveEvent to drag out a line which can, on 
     # mouseReleaseEvent, form a new Relationship or create a new Thing. 

     # If just beginning a drag, 
     if self.dragLine == None: 

      # Create a new lasso line. 
      self.startPosX = event.scenePos().x() 
      self.startPosY = event.scenePos().y() 
      self.dragLine = self.scene().addLine(
         self.startPosX, 
         self.startPosY, 
         event.scenePos().x(), 
         event.scenePos().y(), 
         QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine) 
         ) 

      # Create a new lasso circle at the location of the drag position. 
      self.dragCircle = QtGui.QGraphicsEllipseItem(-5, -5, 10, 10) 
      self.dragCircle.setPos(event.scenePos().x(), 
            event.scenePos().y()) 
      self.scene().addItem(self.dragCircle) 

     # If a drag is already in progress, 
     else: 

      # Move the lasso line and circle to the drag position. 
      self.dragLine.setLine(QtCore.QLineF(self.startPosX, 
               self.startPosY, 
               event.scenePos().x(), 
               event.scenePos().y())) 
      self.dragCircle.setPos(event.scenePos().x(), 
            event.scenePos().y()) 


    def mouseReleaseEvent(self, event): 

     # If the line already exists, 
     if self.dragLine != None: 

      # If the released button was the right mouse button, 
      if event.button() == QtCore.Qt.RightButton: 

       # Clean up the link-drag graphics. 
       self.scene().removeItem(self.dragLine) 
       self.dragLine = None 
       self.scene().removeItem(self.dragCircle) 
       self.dragCircle = None 

       # Create the related Thing. 
       # Display input box querying for name value. 
       entry, ok = QtGui.QInputDialog.getText(None, 'Enter some info: ', 
              'Input:', QtGui.QLineEdit.Normal, '') 

       return 


if __name__ == "__main__": 

    app = QtGui.QApplication(sys.argv) 
    newWindow = Window() 
    sys.exit(app.exec_()) 
+0

À titre expérimental, essayez d'appeler la méthode de classe de base au début de votre implémentation, c'est-à-dire 'super(). MouseReleaseEvent (event)'. Vous pouvez également essayer d'appeler 'event.ignore()' avant l'appel de la classe de base. L'idée est de laisser tout comportement par défaut se produire (ou de l'ignorer explicitement) avant de faire vos propres trucs. – ekhumoro

+0

Aucun changement lorsque j'appelle la méthode de classe de base, même avec event.ignore() avant elle. Cependant, je ne suis pas complètement surpris, car la méthode de classe de base ne produisait pas ces artefacts avant d'avoir ajouté QInputDialog (et aussi, l'artefact "(* check *) Exit" n'est pas ce que j'ai vu auparavant dans le comportement de ces vues et objets graphiques – Grav

+0

Pouvez-vous fournir un exemple minimal et autonome pour que d'autres personnes puissent essayer de reproduire le problème? Sinon, vous forcez les gens à recourir à des devinettes – ekhumoro

Répondre

0

Il n'y avait pas une réponse directe à la cause de ce bug, mais en utilisant un QTimer.singleShot() pour appeler la boîte de dialogue (en combinaison avec un QSignalMapper afin d'entrer des paramètres) est une solution de contournement fonctionnelle qui sépare le dialogue de la méthode dans laquelle le bogue se produisait. Merci à @Avaris pour celui-ci.

0

C'est une supposition de ma part, mais j'ai vu ce genre de chose bizarre avant.

Certains widgets Qt ont un comportement par défaut sur certains types d'événements. Je n'ai jamais utilisé QGraphicsView, mais la valeur par défaut pour un clic droit est souvent d'ouvrir un menu contextuel (généralement inutile, d'après mon expérience). Cela peut se produire dans votre cas, ce qui expliquerait pourquoi vous ne voyez cela que lorsqu'il y a un clic droit.

Vous pouvez supprimer le comportement par défaut Qt en appelant event.ignore() avant le retour de mouseReleaseEvent.

+0

Je souhaite que ce fut le cas, @ Paul_Cornelius! Malheureusement ajouter un event.ignore() avant le retour (ou ailleurs dans la méthode) ne résout pas le problème ... – Grav