【问题标题】:Qt menu artifact when calling input dialog调用输入对话框时的Qt菜单工件
【发布时间】:2018-02-11 02:22:19
【问题描述】:

我正在构建一个 PyQt 应用程序,它应该在 QGraphicsView 上接收鼠标右键单击拖动,绘制一个“套索”(一条从拖动原点延伸到鼠标位置的线,以及鼠标位置的一个圆圈),然后,在释放鼠标时,擦除套索图形并为应用程序的下一部分显示一个输入对话框。

由于某种原因,当我在输入对话框上使用鼠标单击“确定”时,包含套索的 QGraphicsView 上会出现一个菜单工件。菜单工件是一个下拉菜单行,上面写着“(复选标记)退出”。有时它也可能是我的一个自定义 QGraphicsObjects 的上下文菜单 - 但无论出于何种原因,调用对话框然后单击“确定”会导致 QGraphicsView 上出现意外的类似右键单击的事件。

这似乎只发生在方法返回之前的最后一步是 QInputDialog 时 - 将其替换为传递或调用其他方法不会导致工件。如果有人知道导致此问题的原因,我将不胜感激!

这是最少的代码:

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_())

【问题讨论】:

  • 作为一个实验,尝试在你的实现开始时调用基类方法,即super().mouseReleaseEvent(event)。您也可以尝试在基类调用之前调用event.ignore()。这个想法是让任何默认行为发生(或明确忽略它),然后再做自己的事情。
  • 调用基类方法时没有变化,即使在它之前使用 event.ignore() 也是如此。然而,我并不完全感到惊讶,因为在我添加 QInputDialog 之前,基类方法不会产生这些工件(而且,“(复选标记)退出”工件不是我的任何东西)在这些视图和图形对象的行为中已经看到过。
  • 您能否提供一个最小的、独立的示例,以便其他人可以尝试重现该问题?否则,您只是在强迫人们进行猜测。
  • 添加了一个最小的示例代码 - 感谢@ekhumoro!
  • 我无法重现这个。另外,我看不到该示例如何生成您提到的工件,因为菜单是由您自己的应用程序创建的,而不是由 Qt 创建的。您是否通过某种 IDE 运行代码?如果是这样,请尝试在控制台(或命令窗口,如果您在 Windows 上)中将其作为独立脚本运行。

标签: python qt pyqt qgraphicsview


【解决方案1】:

这是我的猜测,但我以前见过这种奇怪的事情。

一些 Qt 小部件在某些类型的事件上具有默认行为。我从未使用过 QGraphicsView,但通常右键单击的默认设置是打开上下文相关的弹出菜单(根据我的经验,通常没用)。在您的情况下可能会发生这种情况,这可以解释为什么您只有在右键单击时才能看到这一点。

你可以在从mouseReleaseEvent.返回之前调用event.ignore()来抑制默认的Qt行为

【讨论】:

  • 我希望是这样,@Paul_Cornelius!不幸的是,在返回之前(或方法中的任何其他地方)添加 event.ignore() 并不能解决问题......
【解决方案2】:

对于这个错误的原因没有直接的答案,但使用 QTimer.singleShot() 调用对话框(结合 QSignalMapper 以输入参数)是将对话框与发生错误的方法。感谢@Avaris 的这个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多