pythonpyqtqt-designersignals-slots

Linking actions to menu bar in PyQt from Qt Designer


I'm new to QT Designer and PyQt, but I seem to be trying to do something either too simple to be mentioned or too rare!

I created a simple window using QT Designer. In that window there is two menu options; one should close the window, the other should open another window.

I converted the ui into a python file with the pyuic5 command.

This is the code I get:

    # -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'Win1.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(441, 305)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 441, 22))
        self.menubar.setObjectName("menubar")
        self.menuClosing = QtWidgets.QMenu(self.menubar)
        self.menuClosing.setObjectName("menuClosing")
        self.menuOpen_Win_2 = QtWidgets.QMenu(self.menubar)
        self.menuOpen_Win_2.setObjectName("menuOpen_Win_2")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menubar.addAction(self.menuClosing.menuAction())
        self.menubar.addAction(self.menuOpen_Win_2.menuAction())

        self.retranslateUi(MainWindow)
        self.menuClosing.triggered['QAction*'].connect(MainWindow.close) # type: ignore
        self.menuOpen_Win_2.triggered['QAction*'].connect(MainWindow.open) # type: ignore
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.menuClosing.setTitle(_translate("MainWindow", "Closing"))
        self.menuOpen_Win_2.setTitle(_translate("MainWindow", "Open Win #2"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

New in QT Designer I have assigned the "close()" slot to Closing and I created a new slot "open()" that I linked to Open Win #2.

Obviously, neither work.

It seems there is a different logic than there is when assigning functions to submenus (where linking close() to it does work).

Does anyone knows how I should go about to do this?


Solution

  • Designer doesn't allow to add basic actions to a QMenuBar.

    In fact, both the "Edit Signals/Slots" mode and the "Signal/Slot Editor" only allow interacting with widgets: QActions are not widgets.

    The only way to achieve this is by code, and by directly adding a real QAction to the menubar.

    Remove those (probably empty) menus from the UI, rebuild the code with pyuic and then do something like this after (assuming that the output file is named win1.py):

    from PyQt5 import QtWidgets
    from win1 import Ui_MainWindow
    from win2 import Ui_MainWindow2
    
    class Window(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, parent=None):
            super().__init__(parent=parent)
            self.setupUi(self)
            self.closeAction = QtWidgets.QAction('Closing', self)
            self.menuBar().addAction(self.closeAction)
            self.openWin2Action = QtWidgets.QAction('Open Win #2', self)
            self.menuBar().addAction(self.openWin2Action)
    
            self.closeAction.triggered.connect(self.close)
            self.openWin2Action.triggered.connect(self.openWin2)
    
        def openWin2(self):
            self.win2 = Window2()
            self.win2.show()
    
    
    class Window2(QtWidgets.QMainWindow, Ui_MainWindow2):
        def __init__(self):
            super().__init__()
            self.setupUi(self)
    
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.show()
        sys.exit(app.exec())
    

    Notes: