PyQt6 custom signals and slots connection

59 views Asked by At

I have a button as a separate class and main window class. On main window there are 2 QlineEdit widgets. I want to take text from them and process it somehow when button clicked. The processing should happen in button class, besause i want to try slots and signals connections. ButtonWidget class accepts text from QLineEdits and returns it somehow. Returned text then shows in QLabel. For now text dont changes, though text emits to the processing slot-function. Then it should emit back, but it is not working.

import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QLabel, QLineEdit, QWidget
from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot


class ButtonWidget(QPushButton):
    accepted_text = Signal(str, str)

    def __init__(self):
        super().__init__()
        self.setText("Accept Text")

    @Slot(str, str)
    def accept_text(self, text1, text2):
        text1 = text1.upper()
        text2 = text2.title()
        self.accepted_text.emit(text1, text2)


class MainWindow(QWidget):
    pushed_text = Signal(str, str)

    def __init__(self):
        super().__init__()

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.line1 = QLineEdit(placeholderText="enter text")
        self.line2 = QLineEdit(placeholderText="enter text")

        self.button_widget = ButtonWidget()

        self.label = QLabel("")

        layout.addWidget(self.line1)
        layout.addWidget(self.line2)
        layout.addWidget(self.button_widget)
        layout.addWidget(self.label)

        self.pushed_text.connect(self.button_widget.accept_text)
        self.button_widget.clicked.connect(self.change_label)

        self.show()

    def change_label(self):
        text1 = self.line1.text()
        text2 = self.line2.text()
        self.pushed_text.emit(text1, text2)
        self.label.setText(text1 + " " + text2)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

I tried to connect function accept_text() from ButtonWidget class with pushed_text signal from QLineEdit from main Window class. accept_text() function should return processed text somehow.

resulting window

it should be STACK Overflow instead of stack overflow. Is there any way to properly connect slots and signals between classes?

1

There are 1 answers

4
Lethnis On

I guess i kinda figured it out, but it is kinda messy. Maybe there is a better way. All this is very confusing, if you know better way, please let me know. What i changed:

class ButtonWidget(QPushButton):
    accepted_text = Signal(str, str)
    returned_text = Signal(str, str)

    def __init__(self):
        super().__init__()
        self.setText("Accept Text")

        self.accepted_text.connect(self.accept_text)

    @Slot(str, str)
    def accept_text(self, text1, text2):
        text1 = text1.upper()
        text2 = text2.title()
        self.returned_text.emit(text1, text2)

I added new signal returned_text to the ButtonWidget. I connected accepted_text signal with the accept_text slot-function. This function now emit returned_text signal.

In MainWindow window i deleted pushed_text signal and added the following code:

    self.button_widget.returned_text.connect(self.update_label)
    self.button_widget.clicked.connect(self.change_label)

    self.show()

def update_label(self, text1, text2):
    self.label.setText(text1 + " " + text2)

def change_label(self):
    text1 = self.line1.text()
    text2 = self.line2.text()
    self.button_widget.accepted_text.emit(text1, text2)

I connected returned_text signal with the update_label function. Button clicked event still connected with change_label function. Inside that function we get elements we want to change and emit accepted_text that is connected with accept_text slot-function inside ButtonWidget.

Now it works as i wanted it to work.

Result

Here is the full code:

import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QLabel, QLineEdit, QWidget
from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot


class ButtonWidget(QPushButton):
    accepted_text = Signal(str, str)
    returned_text = Signal(str, str)

    def __init__(self):
        super().__init__()
        self.setText("Accept Text")

        self.accepted_text.connect(self.accept_text)

    @Slot(str, str)
    def accept_text(self, text1, text2):
        text1 = text1.upper()
        text2 = text2.title()
        self.returned_text.emit(text1, text2)


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.line1 = QLineEdit(placeholderText="enter text")
        self.line2 = QLineEdit(placeholderText="enter text")

        self.button_widget = ButtonWidget()

        self.label = QLabel("")

        layout.addWidget(self.line1)
        layout.addWidget(self.line2)
        layout.addWidget(self.button_widget)
        layout.addWidget(self.label)

        self.button_widget.returned_text.connect(self.update_label)
        self.button_widget.clicked.connect(self.change_label)

        self.show()

   def update_label(self, text1, text2):
        self.label.setText(text1 + " " + text2)

   def change_label(self):
        text1 = self.line1.text()
        text2 = self.line2.text()
        self.button_widget.accepted_text.emit(text1, text2)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())