SketchyManDan SketchyManDan - 1 month ago 5
Python Question

Why is PyQt executing my actions three times?

I'm still kind of new to PyQt but I really have no idea why this is happening.

I have a Mainwindow that I create like this:

class MainWindow(QtGui.QMainWindow):
#initialize
def __init__(self):
#Call parent constructor
super(MainWindow, self).__init__()

#Load the interface
self.ui = uic.loadUi(r"Form Files/rsleditor.ui")

#Show the ui
self.ui.show()


and when I wanted to override the close event with:

def closeEvent(self, event):
quit_msg = "Are you sure you want to exit the program?"
reply = QtGui.QMessageBox.question(self, 'Message',
quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

if reply == QtGui.QMessageBox.Yes:
self.saveSettings()
event.accept()
else:
event.ignore()


I read I had to change the
uic.loadUI
call to:

self.ui = uic.loadUi(r"Form Files/rsleditor.ui", self)


But when I do this, all of my actions start being set off three times. I'm pretty sure I'm setting up the signals and slots correctly as they were working before adding this. Any help?

The pyuic file:

RSLEditorClass.setIconSize(QtCore.QSize(24, 24))
self.centralWidget = QtGui.QWidget(RSLEditorClass)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralWidget.sizePolicy().hasHeightForWidth())
self.centralWidget.setSizePolicy(sizePolicy)
self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
self.vLayMain = QtGui.QVBoxLayout(self.centralWidget)
self.vLayMain.setObjectName(_fromUtf8("vLayMain"))
self.hLayFilePath = QtGui.QHBoxLayout()
self.hLayFilePath.setObjectName(_fromUtf8("hLayFilePath"))
self.lbFilePath = QtGui.QLabel(self.centralWidget)
self.lbFilePath.setObjectName(_fromUtf8("lbFilePath"))
self.hLayFilePath.addWidget(self.lbFilePath)
self.txtFilePath = QtGui.QLineEdit(self.centralWidget)
self.txtFilePath.setObjectName(_fromUtf8("txtFilePath"))
self.hLayFilePath.addWidget(self.txtFilePath)
self.vLayMain.addLayout(self.hLayFilePath)
self.splitTxt = QtGui.QSplitter(self.centralWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.splitTxt.sizePolicy().hasHeightForWidth())
self.splitTxt.setSizePolicy(sizePolicy)
self.splitTxt.setLineWidth(0)
self.splitTxt.setMidLineWidth(0)
self.splitTxt.setOrientation(QtCore.Qt.Vertical)
self.splitTxt.setHandleWidth(10)
self.splitTxt.setObjectName(_fromUtf8("splitTxt"))
self.tabMain = QtGui.QTabWidget(self.splitTxt)
self.tabMain.setBaseSize(QtCore.QSize(0, 0))
self.tabMain.setElideMode(QtCore.Qt.ElideNone)
self.tabMain.setTabsClosable(True)
self.tabMain.setMovable(False)
self.tabMain.setObjectName(_fromUtf8("tabMain"))
self.tabOutput = QtGui.QTabWidget(self.splitTxt)
self.tabOutput.setObjectName(_fromUtf8("tabOutput"))
self.tabRSLOut = QtGui.QWidget()
self.tabRSLOut.setObjectName(_fromUtf8("tabRSLOut"))
self.vLayRSL = QtGui.QVBoxLayout(self.tabRSLOut)
self.vLayRSL.setObjectName(_fromUtf8("vLayRSL"))
self.txtRSLOut = QtGui.QTextEdit(self.tabRSLOut)
self.txtRSLOut.setTextInteractionFlags(QtCore.Qt.TextEditable)
self.txtRSLOut.setObjectName(_fromUtf8("txtRSLOut"))
self.vLayRSL.addWidget(self.txtRSLOut)
self.tabOutput.addTab(self.tabRSLOut, _fromUtf8(""))
self.tabRIBOut = QtGui.QWidget()
self.tabRIBOut.setObjectName(_fromUtf8("tabRIBOut"))
self.vLayRib = QtGui.QVBoxLayout(self.tabRIBOut)
self.vLayRib.setObjectName(_fromUtf8("vLayRib"))
self.txtRIBOut = QtGui.QTextEdit(self.tabRIBOut)
self.txtRIBOut.setTextInteractionFlags(QtCore.Qt.TextEditable)
self.txtRIBOut.setObjectName(_fromUtf8("txtRIBOut"))
self.vLayRib.addWidget(self.txtRIBOut)
self.tabOutput.addTab(self.tabRIBOut, _fromUtf8(""))
self.vLayMain.addWidget(self.splitTxt)
RSLEditorClass.setCentralWidget(self.centralWidget)
self.menuBar = QtGui.QMenuBar(RSLEditorClass)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 750, 21))
self.menuBar.setObjectName(_fromUtf8("menuBar"))
self.menuFile = QtGui.QMenu(self.menuBar)
self.menuFile.setObjectName(_fromUtf8("menuFile"))
self.menuRecent_Files = QtGui.QMenu(self.menuFile)
self.menuRecent_Files.setObjectName(_fromUtf8("menuRecent_Files"))
self.menuEdit = QtGui.QMenu(self.menuBar)
self.menuEdit.setObjectName(_fromUtf8("menuEdit"))
self.menuSearch_Options = QtGui.QMenu(self.menuEdit)
self.menuSearch_Options.setObjectName(_fromUtf8("menuSearch_Options"))
self.menuView = QtGui.QMenu(self.menuBar)
self.menuView.setObjectName(_fromUtf8("menuView"))
self.menuSearch = QtGui.QMenu(self.menuBar)
self.menuSearch.setObjectName(_fromUtf8("menuSearch"))
self.menuDebug = QtGui.QMenu(self.menuBar)
self.menuDebug.setObjectName(_fromUtf8("menuDebug"))
self.menuHelp = QtGui.QMenu(self.menuBar)
self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
RSLEditorClass.setMenuBar(self.menuBar)
self.mainToolBar = QtGui.QToolBar(RSLEditorClass)
self.mainToolBar.setObjectName(_fromUtf8("mainToolBar"))
RSLEditorClass.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
self.actionNew = QtGui.QAction(RSLEditorClass)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionNew.setIcon(icon1)
self.actionNew.setObjectName(_fromUtf8("actionNew"))
self.actionOpen = QtGui.QAction(RSLEditorClass)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/open.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionOpen.setIcon(icon2)
self.actionOpen.setObjectName(_fromUtf8("actionOpen"))
self.actionSave = QtGui.QAction(RSLEditorClass)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/save.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionSave.setIcon(icon3)
self.actionSave.setObjectName(_fromUtf8("actionSave"))
self.actionSave_As = QtGui.QAction(RSLEditorClass)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/save as.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionSave_As.setIcon(icon4)
self.actionSave_As.setObjectName(_fromUtf8("actionSave_As"))
self.actionUndo = QtGui.QAction(RSLEditorClass)
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/undo.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionUndo.setIcon(icon5)
self.actionUndo.setObjectName(_fromUtf8("actionUndo"))
self.actionRedo = QtGui.QAction(RSLEditorClass)
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/redo.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionRedo.setIcon(icon6)
self.actionRedo.setObjectName(_fromUtf8("actionRedo"))
self.actionCut = QtGui.QAction(RSLEditorClass)
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/cut.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionCut.setIcon(icon7)
self.actionCut.setObjectName(_fromUtf8("actionCut"))
self.actionCopy = QtGui.QAction(RSLEditorClass)
icon8 = QtGui.QIcon()
icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/copy.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionCopy.setIcon(icon8)
self.actionCopy.setObjectName(_fromUtf8("actionCopy"))
self.actionPaste = QtGui.QAction(RSLEditorClass)
icon9 = QtGui.QIcon()
icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/paste.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionPaste.setIcon(icon9)
self.actionPaste.setObjectName(_fromUtf8("actionPaste"))
self.actionSelect_All = QtGui.QAction(RSLEditorClass)
self.actionSelect_All.setObjectName(_fromUtf8("actionSelect_All"))
self.actionCompile = QtGui.QAction(RSLEditorClass)
icon10 = QtGui.QIcon()
icon10.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/compile.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionCompile.setIcon(icon10)
self.actionCompile.setObjectName(_fromUtf8("actionCompile"))
self.actionFind_Replace = QtGui.QAction(RSLEditorClass)
self.actionFind_Replace.setObjectName(_fromUtf8("actionFind_Replace"))
self.actionPreferences = QtGui.QAction(RSLEditorClass)
icon11 = QtGui.QIcon()
icon11.addPixmap(QtGui.QPixmap(_fromUtf8(":/icons/prefs.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionPreferences.setIcon(icon11)
self.actionPreferences.setObjectName(_fromUtf8("actionPreferences"))
self.actionAdd_Shader_Path = QtGui.QAction(RSLEditorClass)
self.actionAdd_Shader_Path.setObjectName(_fromUtf8("actionAdd_Shader_Path"))
self.actionAdd_Textures_Path = QtGui.QAction(RSLEditorClass)
self.actionAdd_Textures_Path.setObjectName(_fromUtf8("actionAdd_Textures_Path"))
self.actionAdd_Archives_Path = QtGui.QAction(RSLEditorClass)
self.actionAdd_Archives_Path.setObjectName(_fromUtf8("actionAdd_Archives_Path"))
self.actionAdd_PointCloud_Path = QtGui.QAction(RSLEditorClass)
self.actionAdd_PointCloud_Path.setObjectName(_fromUtf8("actionAdd_PointCloud_Path"))
self.actionAdd_BrickMap_Path = QtGui.QAction(RSLEditorClass)
self.actionAdd_BrickMap_Path.setObjectName(_fromUtf8("actionAdd_BrickMap_Path"))
self.actionAdd_PhotonMap_Path = QtGui.QAction(RSLEditorClass)
self.actionAdd_PhotonMap_Path.setObjectName(_fromUtf8("actionAdd_PhotonMap_Path"))
self.actionEditor_Docs = QtGui.QAction(RSLEditorClass)
self.actionEditor_Docs.setObjectName(_fromUtf8("actionEditor_Docs"))
self.actionDelight_Docs = QtGui.QAction(RSLEditorClass)
self.actionDelight_Docs.setObjectName(_fromUtf8("actionDelight_Docs"))
self.actionPRMan_Docs = QtGui.QAction(RSLEditorClass)
self.actionPRMan_Docs.setObjectName(_fromUtf8("actionPRMan_Docs"))
self.actionFundza = QtGui.QAction(RSLEditorClass)
self.actionFundza.setObjectName(_fromUtf8("actionFundza"))
self.actionColor_Picker = QtGui.QAction(RSLEditorClass)
self.actionColor_Picker.setObjectName(_fromUtf8("actionColor_Picker"))
self.actionClose_Tab = QtGui.QAction(RSLEditorClass)
self.actionClose_Tab.setObjectName(_fromUtf8("actionClose_Tab"))
self.actionExit = QtGui.QAction(RSLEditorClass)
self.actionExit.setObjectName(_fromUtf8("actionExit"))
self.menuRecent_Files.addSeparator()
self.menuFile.addAction(self.actionNew)
self.menuFile.addAction(self.actionOpen)
self.menuFile.addAction(self.menuRecent_Files.menuAction())
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionSave)
self.menuFile.addAction(self.actionSave_As)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionClose_Tab)
self.menuFile.addAction(self.actionExit)
self.menuSearch_Options.addAction(self.actionAdd_Shader_Path)
self.menuSearch_Options.addAction(self.actionAdd_Textures_Path)
self.menuSearch_Options.addAction(self.actionAdd_Archives_Path)
self.menuSearch_Options.addAction(self.actionAdd_PointCloud_Path)
self.menuSearch_Options.addAction(self.actionAdd_BrickMap_Path)
self.menuSearch_Options.addAction(self.actionAdd_PhotonMap_Path)
self.menuEdit.addAction(self.actionUndo)
self.menuEdit.addAction(self.actionRedo)
self.menuEdit.addSeparator()
self.menuEdit.addAction(self.actionCut)
self.menuEdit.addAction(self.actionCopy)
self.menuEdit.addAction(self.actionPaste)
self.menuEdit.addSeparator()
self.menuEdit.addAction(self.actionSelect_All)
self.menuEdit.addSeparator()
self.menuEdit.addAction(self.menuSearch_Options.menuAction())
self.menuEdit.addAction(self.actionColor_Picker)
self.menuSearch.addAction(self.actionFind_Replace)
self.menuDebug.addAction(self.actionCompile)
self.menuDebug.addSeparator()
self.menuDebug.addAction(self.actionPreferences)
self.menuHelp.addAction(self.actionEditor_Docs)
self.menuHelp.addSeparator()
self.menuHelp.addAction(self.actionDelight_Docs)
self.menuHelp.addSeparator()
self.menuHelp.addAction(self.actionPRMan_Docs)
self.menuHelp.addSeparator()
self.menuHelp.addAction(self.actionFundza)
self.menuBar.addAction(self.menuFile.menuAction())
self.menuBar.addAction(self.menuEdit.menuAction())
self.menuBar.addAction(self.menuView.menuAction())
self.menuBar.addAction(self.menuSearch.menuAction())
self.menuBar.addAction(self.menuDebug.menuAction())
self.menuBar.addAction(self.menuHelp.menuAction())
self.mainToolBar.addAction(self.actionNew)
self.mainToolBar.addAction(self.actionOpen)
self.mainToolBar.addAction(self.actionSave)
self.mainToolBar.addAction(self.actionSave_As)
self.mainToolBar.addAction(self.actionUndo)
self.mainToolBar.addAction(self.actionRedo)
self.mainToolBar.addAction(self.actionCut)
self.mainToolBar.addAction(self.actionCopy)
self.mainToolBar.addAction(self.actionPaste)
self.mainToolBar.addAction(self.actionCompile)
self.mainToolBar.addAction(self.actionPreferences)

self.retranslateUi(RSLEditorClass)
self.tabMain.setCurrentIndex(-1)
self.tabOutput.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(RSLEditorClass)

def retranslateUi(self, RSLEditorClass):
RSLEditorClass.setWindowTitle(_translate("RSLEditorClass", "RSLEditor", None))
self.lbFilePath.setText(_translate("RSLEditorClass", "File Path:", None))
self.tabOutput.setTabText(self.tabOutput.indexOf(self.tabRSLOut), _translate("RSLEditorClass", "RSL Output", None))
self.tabOutput.setTabText(self.tabOutput.indexOf(self.tabRIBOut), _translate("RSLEditorClass", "RIB Output", None))
self.menuFile.setTitle(_translate("RSLEditorClass", "File", None))
self.menuRecent_Files.setTitle(_translate("RSLEditorClass", "Recent Files", None))
self.menuEdit.setTitle(_translate("RSLEditorClass", "Edit", None))
self.menuSearch_Options.setTitle(_translate("RSLEditorClass", "Search Options", None))
self.menuView.setTitle(_translate("RSLEditorClass", "View", None))
self.menuSearch.setTitle(_translate("RSLEditorClass", "Search", None))
self.menuDebug.setTitle(_translate("RSLEditorClass", "Debug", None))
self.menuHelp.setTitle(_translate("RSLEditorClass", "Help", None))
self.actionNew.setText(_translate("RSLEditorClass", "New", None))
self.actionNew.setToolTip(_translate("RSLEditorClass", "Create a new file", None))
self.actionNew.setShortcut(_translate("RSLEditorClass", "Ctrl+N", None))
self.actionOpen.setText(_translate("RSLEditorClass", "Open", None))
self.actionOpen.setToolTip(_translate("RSLEditorClass", "Open a file", None))
self.actionOpen.setShortcut(_translate("RSLEditorClass", "Ctrl+O", None))
self.actionSave.setText(_translate("RSLEditorClass", "Save", None))
self.actionSave.setToolTip(_translate("RSLEditorClass", "Save the current file", None))
self.actionSave.setShortcut(_translate("RSLEditorClass", "Ctrl+S", None))
self.actionSave_As.setText(_translate("RSLEditorClass", "Save As", None))
self.actionSave_As.setToolTip(_translate("RSLEditorClass", "Save as a new file", None))
self.actionSave_As.setShortcut(_translate("RSLEditorClass", "Ctrl+Alt+S", None))
self.actionUndo.setText(_translate("RSLEditorClass", "Undo", None))
self.actionUndo.setToolTip(_translate("RSLEditorClass", "Undo last action", None))
self.actionUndo.setShortcut(_translate("RSLEditorClass", "Ctrl+Z", None))
self.actionRedo.setText(_translate("RSLEditorClass", "Redo", None))
self.actionRedo.setToolTip(_translate("RSLEditorClass", "Redo last action", None))
self.actionRedo.setShortcut(_translate("RSLEditorClass", "Shift+Z", None))
self.actionCut.setText(_translate("RSLEditorClass", "Cut", None))
self.actionCut.setToolTip(_translate("RSLEditorClass", "Cut selected text", None))
self.actionCut.setShortcut(_translate("RSLEditorClass", "Ctrl+X", None))
self.actionCopy.setText(_translate("RSLEditorClass", "Copy", None))
self.actionCopy.setToolTip(_translate("RSLEditorClass", "Copy selected text", None))
self.actionCopy.setShortcut(_translate("RSLEditorClass", "Ctrl+C", None))
self.actionPaste.setText(_translate("RSLEditorClass", "Paste", None))
self.actionPaste.setToolTip(_translate("RSLEditorClass", "Paste text", None))
self.actionPaste.setShortcut(_translate("RSLEditorClass", "Ctrl+V", None))
self.actionSelect_All.setText(_translate("RSLEditorClass", "Select All", None))
self.actionSelect_All.setToolTip(_translate("RSLEditorClass", "Select all text", None))
self.actionSelect_All.setShortcut(_translate("RSLEditorClass", "Ctrl+A", None))
self.actionCompile.setText(_translate("RSLEditorClass", "Compile", None))
self.actionCompile.setToolTip(_translate("RSLEditorClass", "Compile current document", None))
self.actionCompile.setShortcut(_translate("RSLEditorClass", "Alt+E", None))
self.actionFind_Replace.setText(_translate("RSLEditorClass", "Find/Replace", None))
self.actionFind_Replace.setToolTip(_translate("RSLEditorClass", "Open find/replace dialog", None))
self.actionFind_Replace.setShortcut(_translate("RSLEditorClass", "Ctrl+F", None))
self.actionPreferences.setText(_translate("RSLEditorClass", "Preferences", None))
self.actionPreferences.setToolTip(_translate("RSLEditorClass", "Open the preferences dialog", None))
self.actionPreferences.setShortcut(_translate("RSLEditorClass", "Ctrl+P", None))
self.actionAdd_Shader_Path.setText(_translate("RSLEditorClass", "Add Shader Path", None))
self.actionAdd_Textures_Path.setText(_translate("RSLEditorClass", "Add Textures Path", None))
self.actionAdd_Archives_Path.setText(_translate("RSLEditorClass", "Add Archives Path", None))
self.actionAdd_PointCloud_Path.setText(_translate("RSLEditorClass", "Add PointCloud Path", None))
self.actionAdd_BrickMap_Path.setText(_translate("RSLEditorClass", "Add BrickMap Path", None))
self.actionAdd_PhotonMap_Path.setText(_translate("RSLEditorClass", "Add PhotonMap Path", None))
self.actionEditor_Docs.setText(_translate("RSLEditorClass", "Editor Docs", None))
self.actionDelight_Docs.setText(_translate("RSLEditorClass", "3Delight Docs", None))
self.actionPRMan_Docs.setText(_translate("RSLEditorClass", "PRMan Docs", None))
self.actionFundza.setText(_translate("RSLEditorClass", "Fundza", None))
self.actionColor_Picker.setText(_translate("RSLEditorClass", "Color Picker", None))
self.actionColor_Picker.setShortcut(_translate("RSLEditorClass", "Ctrl+I", None))
self.actionClose_Tab.setText(_translate("RSLEditorClass", "Close Tab", None))
self.actionExit.setText(_translate("RSLEditorClass", "Exit", None))

import rsleditor_rc

Answer

If you scroll down to the bottom of the setupUi method in the ui module, you'll see this line:

    QtCore.QMetaObject.connectSlotsByName(RSLEditorClass)

What this does, is to automatically connect signals to slots based on the format of the slot names. The format of the slot name is:

    on_[object name]_[signal name]

So looking at the way you're connecting your actions:

    self.ui.actionNew.triggered.connect(self.on_actionNew_triggered)

it should be clear that you're using this format when naming your slots, and that that is where the problem lies. But why does this cause the slot to be called three times? Well, in PyQt, the triggered signal has two overloads: one which sends the default checked parameter, and one which doesn't. If you don't specify which one of these you want to connect to, both overloads will get connected. So in your case, what happens is that on_actionNew_triggered gets connected twice by connectSlotsByName and once by your own explicit connection, making three in all. And presumably, a similar story can be told for the other actions.

To fix this, you can either rename your slots so they don't use the auto-connection format:

    self.ui.actionNew.triggered.connect(self.handleActionNew)
    ...

    def handleActionNew(self):
    ...

or get rid of the explicit connection, and use the pyqtSlot decorator to select the right overload for auto-connection:

    @QtCore.pyqtSlot()
    def on_actionNew_triggered(self):
    ...

or:

    @QtCore.pyqtSlot(bool)
    def on_actionNew_triggered(self, checked):
    ...