Сигналы в Pyside6

Я не могу понять, почему сигналы не работают. В PyQt5 этот код работал (разница в том, что вместо Signal был pyqtSignal).

При нажатии на кнопку TextEdit должен отображать сообщение о подключении к устройству, если заменить pyside на pyqt, код будет работать как надо

import sys
from PySide6.QtCore import *
from PySide6.QtWidgets import *


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(188, 267)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setObjectName(u"pushButton")
        self.pushButton.setGeometry(QRect(50, 140, 75, 24))
        self.textEdit = QTextEdit(self.centralwidget)
        self.textEdit.setObjectName(u"textEdit")
        self.textEdit.setGeometry(QRect(30, 40, 104, 71))
        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)
    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self, parent=None)
        self.dragPos = None
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.show()

def update_text(value, textEdit):
    textEdit.setText(textEdit.toPlainText() + value)
    textEdit.verticalScrollBar().setValue(textEdit.verticalScrollBar().maximum())
class account(QThread):
    textUpdate = Signal(str, QTextEdit)

    def __init__(self):
        super().__init__(parent=None)
        self.textUpdate.connect(update_text)

    def run(self):
        print("thread is work")
        self.textUpdate.emit("Connect to device\n", ui.textEdit)
        
if __name__ == "__main__":
    app = QApplication()
    acc_instance = account()
    main = MainWindow()
    ui = main.ui
    ui.pushButton.clicked.connect(acc_instance.start)
    sys.exit(app.exec_())

P.S. Я знаю, что метод переопределения запуска неверен.

P.S.S Добавил небольшой пример


person Mikhail Drozdov    schedule 23.04.2021    source источник
comment
Использование декоратора слотов работает только для методов подклассов QObject, его использование для сиротских функций бесполезно.   -  person musicamante    schedule 23.04.2021
comment
Ладно, удалил, но как заставить программу работать?   -  person Mikhail Drozdov    schedule 23.04.2021
comment
@MikhailDrozdov, пожалуйста, предоставьте минимальный воспроизводимый пример   -  person eyllanesc    schedule 23.04.2021
comment
@eyllanesc Добавил пример   -  person Mikhail Drozdov    schedule 23.04.2021


Ответы (1)


В вашем коде есть несколько проблем:

  1. Объем пользовательского интерфейса ограничен, это не глобальная переменная, поэтому вы не можете использовать ее в методе запуска.

  2. Зарегистрированы только некоторые типы данных (что можно сделать только в C++), чтобы их можно было отправлять через сигналы, а в случае с QTextEdit это не так. Обходной путь заключается в поиске родительского класса QTextEdit, который зарегистрирован как QObject или объект.

Но в этом случае я не вижу необходимости отправлять QTextEdit, а только данные, а затем изменять графический интерфейс, чтобы установить его, поскольку это его задача.

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

    @Slot(str)
    def update_text(self, value):
        self.ui.textEdit.setText(self.ui.textEdit.toPlainText() + value)
        self.ui.textEdit.verticalScrollBar().setValue(
            self.ui.textEdit.verticalScrollBar().maximum()
        )


class Account(QThread):
    textUpdate = Signal(str)

    def run(self):
        print("thread is work")
        self.textUpdate.emit("Connect to device\n")


if __name__ == "__main__":
    app = QApplication()

    main = MainWindow()
    acc_instance = Account()

    acc_instance.textUpdate.connect(main.update_text)
    main.ui.pushButton.clicked.connect(acc_instance.start)

    main.show()

    sys.exit(app.exec_())

Примечание. В pyqt6 ваш исходный код также не работает.

Если вы хотите отправлять тексты в несколько QTextEdit, то лучше создать ключ, который связывает каждый тип текста с группой QTextEdit:

from collections import defaultdict
from functools import cached_property


class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self, parent=None)
        self.dragPos = None
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.show()

        self.register("device_viewer", self.ui.textEdit)
        # self.register("another_key", another_textedit)

    def register(self, key, textedit):
        if not isinstance(textedit, QTextEdit):
            raise TypeError(f"{textedit} must be a QTextEdit")
        self.registry_viewers[key].append(textedit)

    @cached_property
    def registry_viewers(self):
        return defaultdict(list)

    @Slot(str, str)
    def update_text(self, key, value):
        for textedit in self.registry_viewers[key]:
            textedit.setText(textedit.toPlainText() + value)
            textedit.verticalScrollBar().setValue(
                textedit.verticalScrollBar().maximum()
            )


class Account(QThread):
    textUpdate = Signal(str, str)

    def run(self):
        print("thread is work")
        self.textUpdate.emit("device_viewer", "Connect to device\n")
        # self.textUpdate.emit("another_key", "message")


if __name__ == "__main__":
    app = QApplication()

    main = MainWindow()
    acc_instance = Account()

    acc_instance.textUpdate.connect(main.update_text)
    main.ui.pushButton.clicked.connect(acc_instance.start)

    sys.exit(app.exec_())
person eyllanesc    schedule 23.04.2021
comment
Странно, код отлично работает на моей машине. О пользовательском интерфейсе: я объявил эту переменную в main, что делает ее глобальной. Так же в моем коде есть несколько таких TextEdit и мне нужна универсальная функция (как в моем примере), ваш код не подходит под мои задачи. - person Mikhail Drozdov; 23.04.2021
comment
@MikhailDrozdov Смотрите обновление. Примечание: по возможности избегайте глобальных переменных (обычно используйте их только для значений конфигурации), поскольку ошибки трудно отлаживать. - person eyllanesc; 23.04.2021