Search code examples
python-3.xpyside2pyside6

how to connect to signal from one class to a slot in another?


How to connect to myQCustomQWidget.connectButton to exampleQMainWindow.setNewText

If the signal/slot are in the same class, i.e exampleQMainWindow I can simply connect them like this:

self.button.clicked.connect(self.setNewText)

But if they are in different classes, How can I connect them?

import sys
from PySide6 import QtGui
from PySide6.QtWidgets import *

class QCustomQWidget(QWidget):
    def __init__(self, parent=None):
        super(QCustomQWidget, self).__init__(parent)
        self.textQVBoxLayout = QVBoxLayout()
        self.textUpQLabel = QLabel()
        self.textDownQLabel = QLabel()
        self.textQVBoxLayout.addWidget(self.textUpQLabel)
        self.textQVBoxLayout.addWidget(self.textDownQLabel)
        self.allQHBoxLayout = QHBoxLayout()
        self.iconQLabel = QLabel()
        self.allQHBoxLayout.addWidget(self.iconQLabel, 0)
        self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1)
        self.setLayout(self.allQHBoxLayout)
        # setStyleSheet
        self.textUpQLabel.setStyleSheet('''
            color: rgb(0, 0, 255);
        ''')
        self.textDownQLabel.setStyleSheet('''
            color: rgb(255, 0, 0);
        ''')

        self.openButton = QPushButton()
        self.allQHBoxLayout.addWidget(self.openButton, 1)

    def setButton(self, index):
        self.openButton.setText(index)

    def connectButton(self, index): # <-----
        self.openButton.clicked.connect()

    def setTextUp(self, text):
        self.textUpQLabel.setText(text)

    def setTextDown(self, text):
        self.textDownQLabel.setText(text)

    def setIcon(self, imagePath):
        self.iconQLabel.setPixmap(QtGui.QPixmap(imagePath))


class exampleQMainWindow(QMainWindow):
    def __init__(self):
        super(exampleQMainWindow, self).__init__()

        # Create QListWidget
        self.table = QTableWidget(self)
        self.table.setColumnCount(3)
        self.setCentralWidget(self.table)
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.setRowCount(6)
        for index, name, icon, btname in [
            (1, 'text1', 'g:\downloads\coffee-icon.png', "alpha"),
            (2, 'text2', 'g:\downloads\coffee-icon.png', "beta"),
            (3, 'text3', 'g:\downloads\coffee-icon.png', "gamma"),
            (4, 'text4', 'g:\downloads\coffee-icon.png', "delta")
            ]:
            # Create QCustomQWidget
            myQCustomQWidget = QCustomQWidget()
            myQCustomQWidget.setTextUp(str(index))
            myQCustomQWidget.setTextDown(name)
            myQCustomQWidget.setButton(str(btname))
            myQCustomQWidget.button_row = index

            myQCustomQWidget.connectButton()  # how to connect it to setNewText ?

            self.table.setCellWidget(index, 1, myQCustomQWidget)
            self.table.setRowHeight(index,90)


    def setNewText(self): # <----------
        print("test") 



app = QApplication(sys.argv)
window = exampleQMainWindow()
window.resize(800,512)
window.show()
sys.exit(app.exec())

Solution

  • Create a custom signal that emits the index, then connect it from the instance that creates the widget, not the other way around.

    class QCustomQWidget(QWidget):
        clicked = Signal(int)
        def __init__(self, index, name, icon, btnName, parent=None):
            super(QCustomQWidget, self).__init__(parent)
            self.index = index
            # ...
            self.openButton.clicked.connect(self.emitClicked)
            self.setTextUp(str(index + 1))
            self.setTextDown(name)
            self.setIcon(icon)
            self.setButton(btnName)
        # ...
    
        def emitClicked(self):
            self.clicked.emit(self.index)
    
    
    class exampleQMainWindow(QMainWindow):
        def __init__(self):
            # ...
            data = [
                ('text1', 'g:\downloads\coffee-icon.png', "alpha"),
                ('text2', 'g:\downloads\coffee-icon.png', "beta"),
                ('text3', 'g:\downloads\coffee-icon.png', "gamma"),
                ('text4', 'g:\downloads\coffee-icon.png', "delta")
                ]
            self.table.setRowCount(len(data))
            for index, (name, icon, btname) in enumerate(data):
                myQCustomQWidget = QCustomQWidget(index, name, icon, btnname)
                myQCustomQWidget.clicked.connect(self.setNewText)
    
                self.table.setCellWidget(index, 1, myQCustomQWidget)
                self.table.setRowHeight(index, 90)
    
        def setNewText(self, index):
            print(index)
    

    Note that signal connections of child objects should usually be done by a parent object, not the other way around. Also, you should not use global references, especially for these situations, otherwise you might have unexpected behavior or exceptions caused by missing references.