pythonpyqt5qmenuqtoolbutton

python pyqt5 Replace QMenu in QToolButton


File: ui.py

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

# Form implementation generated from reading ui file 'ui.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# 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_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 300)
        self.general_deck_mute_toolbutton = QtWidgets.QToolButton(Dialog)
        self.general_deck_mute_toolbutton.setGeometry(QtCore.QRect(60, 40, 101, 45))
        self.general_deck_mute_toolbutton.setMinimumSize(QtCore.QSize(45, 45))
        self.general_deck_mute_toolbutton.setStyleSheet("")
        self.general_deck_mute_toolbutton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
        self.general_deck_mute_toolbutton.setAutoRaise(False)
        self.general_deck_mute_toolbutton.setObjectName("general_deck_mute_toolbutton")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.general_deck_mute_toolbutton.setText(_translate("Dialog", "QToolButton"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

File: main.py

from PyQt5 import QtCore, QtGui, QtWidgets
from ui import Ui_Dialog
import sys

class Main_Program:
    def __init__(self):
        
        app = QtWidgets.QApplication(sys.argv)
        self.Dialog = QtWidgets.QDialog()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self.Dialog)
        self.Dialog.show()
        
        self.deck_1 = {
            "mute":False
        }
        
        self.deck_2 = {
            "mute":False
        }
        
        self.music_clip_deck = {
            "mute":False
        }
        
        self.make_qtoolbutton_menu()
        
        
        sys.exit(app.exec_())
    
    def make_qtoolbutton_menu(self):
        self.mute_toolbutton_menu = QtWidgets.QMenu()
        try:
            self.mute_deck_1_action.disconnect()
        except:
            pass
        self.mute_deck_1_action = QtWidgets.QAction(self.Dialog)
        if self.deck_1["mute"]==0 or self.deck_1["mute"]==False:
            self.mute_deck_1_action.setText("Απενεργοποίηση σίγασης deck 1")
        else:
            self.mute_deck_1_action.setText("Ενεργοποίηση σίγασης στο deck 1")
        self.mute_toolbutton_menu.addAction(self.mute_deck_1_action)
        self.mute_deck_1_action.triggered.connect(self.mute_or_unmute_deck_1)
        
        try:
            self.mute_deck_2_action.disconnect()
        except:
            pass
        self.mute_deck_2_action = QtWidgets.QAction(self.Dialog)
        if self.deck_2["mute"]==0 or self.deck_2["mute"]==False:
            self.mute_deck_2_action.setText("Απενεργοποίηση σίγασης deck 2")
        else:
            self.mute_deck_2_action.setText("Ενεργοποίηση σίγασης στο deck 2")
        self.mute_toolbutton_menu.addAction(self.mute_deck_2_action)
        self.mute_deck_2_action.triggered.connect(self.mute_or_unmute_deck_2)
        
        try:
            self.mute_music_clip_deck_action.disconnect()
        except:
            pass
        self.mute_music_clip_deck_action = QtWidgets.QAction(self.Dialog)
        if self.music_clip_deck["mute"]==0 or self.music_clip_deck["mute"]==False:
            self.mute_music_clip_deck_action.setText("Απενεργοποίηση σίγασης music clip deck")
        else:
            self.mute_music_clip_deck_action.setText("Ενεργοποίηση σίγασης στο music clip deck")
        self.mute_toolbutton_menu.addAction(self.mute_music_clip_deck_action)
        self.mute_music_clip_deck_action.triggered.connect(self.mute_or_unmute_music_clip_deck)
        
        try:
            self.ui.general_deck_mute_toolbutton.disconnect()
        except:
            pass
        self.ui.general_deck_mute_toolbutton.setMenu(self.mute_toolbutton_menu)
        #self..ui.general_deck_mute_toolbutton.clicked.connect(self.mute_menu_clicked)

    
    def mute_or_unmute_deck_1(self):
        self.deck_1["mute"] = not self.deck_1["mute"]
        self.make_qtoolbutton_menu()
        
    def mute_or_unmute_deck_2(self):
        self.deck_2["mute"] = not self.deck_2["mute"]
        self.make_qtoolbutton_menu()
        
    def mute_or_unmute_music_clip_deck(self):
        self.music_clip_deck["mute"] = not self.music_clip_deck["mute"]
        self.make_qtoolbutton_menu()
        
if __name__ == "__main__":
    program = Main_Program()

To reproduce the problem run python main.py and then click in a menu action (from the down arrow).

This error message is appeared in the screen:

QObject::disconnect: Unexpected nullptr parameter
QObject::disconnect: Unexpected nullptr parameter
QObject::disconnect: Unexpected nullptr parameter
QObject::disconnect: Unexpected nullptr parameter
QObject: shared QObject was deleted directly. The program is malformed and may crash.

Solution

  • I see unnecessary to create QMenu and QAction, connect and disconnect them just to change the text. It is enough to create a method that updates the text:

    class Main_Program:
        def __init__(self):
    
            app = QtWidgets.QApplication(sys.argv)
            self.Dialog = QtWidgets.QDialog()
            self.ui = Ui_Dialog()
            self.ui.setupUi(self.Dialog)
            self.Dialog.show()
    
            self.deck_1 = {"mute": False}
    
            self.deck_2 = {"mute": False}
    
            self.music_clip_deck = {"mute": False}
    
            self.make_qtoolbutton_menu()
            self.update_text_qtoolbutton_menu()
    
            sys.exit(app.exec_())
    
        def make_qtoolbutton_menu(self):
            self.mute_toolbutton_menu = QtWidgets.QMenu()
    
            self.mute_deck_1_action = QtWidgets.QAction(self.Dialog)
            self.mute_deck_1_action.triggered.connect(self.mute_or_unmute_deck_1)
            self.mute_toolbutton_menu.addAction(self.mute_deck_1_action)
    
            self.mute_deck_2_action = QtWidgets.QAction(self.Dialog)
            self.mute_deck_2_action.triggered.connect(self.mute_or_unmute_deck_2)
            self.mute_toolbutton_menu.addAction(self.mute_deck_2_action)
    
            self.mute_music_clip_deck_action = QtWidgets.QAction(self.Dialog)
            self.mute_music_clip_deck_action.triggered.connect(
                self.mute_or_unmute_music_clip_deck
            )
            self.mute_toolbutton_menu.addAction(self.mute_music_clip_deck_action)
            self.ui.general_deck_mute_toolbutton.setMenu(self.mute_toolbutton_menu)
    
        def update_text_qtoolbutton_menu(self):
            self.mute_deck_1_action.setText(
                "Ενεργοποίηση σίγασης στο deck 1"
                if self.deck_1["mute"]
                else "Απενεργοποίηση σίγασης deck 1"
            )
            self.mute_deck_2_action.setText(
                "Ενεργοποίηση σίγασης στο deck 2"
                if self.deck_2["mute"]
                else "Απενεργοποίηση σίγασης deck 2"
            )
            self.mute_music_clip_deck_action.setText(
                "Ενεργοποίηση σίγασης στο music clip deck"
                if self.music_clip_deck["mute"]
                else "Απενεργοποίηση σίγασης music clip deck"
            )
    
        def mute_or_unmute_deck_1(self):
            self.deck_1["mute"] = not self.deck_1["mute"]
            self.update_text_qtoolbutton_menu()
    
        def mute_or_unmute_deck_2(self):
            self.deck_2["mute"] = not self.deck_2["mute"]
            self.update_text_qtoolbutton_menu()
    
        def mute_or_unmute_music_clip_deck(self):
            self.music_clip_deck["mute"] = not self.music_clip_deck["mute"]
            self.update_text_qtoolbutton_menu()