Сигнал и слот в пользовательском классе, включая PyQt QWidget, не работают - PullRequest
2 голосов
/ 17 июня 2020

У меня возникли проблемы с настройкой класса, включая QPushButton и QLabel, и я просто хочу установить флажок QPushButton и определить слот для его переключаемого сигнала, кроме того, наследники настраиваемого класса QObject .

Код показан ниже:

import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import pyqtSlot, QObject


class CustomButton(QPushButton):
    def __init__(self, label='', parent=None):
        super().__init__(label, parent)
        self.setCheckable(True)
        self.toggled.connect(self.update)

    def update(self, state):
        if state:
            self.setStyleSheet('background-color: green')
        else:
            self.setStyleSheet('background-color: red')

class ButtonCtrl(QObject):
    def __init__(self,  parent=None, label=''):
        super().__init__()
        if isinstance(parent, QLayout):
            col = QVBoxLayout()
            parent.addLayout(col)
        else:
            col = QVBoxLayout(parent)
        self.text = ['ON', 'OFF']
        self.label = QLabel(label)
        self.button = QPushButton('ON')
        # self.button = CustomButton('ON')
        col.addWidget(self.label)
        col.addWidget(self.button)
        self.button.setCheckable(True)
        self.button.setChecked(True)
        self.button.toggled.connect(self.update)
        self.update(True)
        self.label.setFont(QFont('Microsoft YaHei', 14))
        self.button.setFont(QFont('Microsoft YaHei', 12, True))
        self.button.toggle()

    # @pyqtSlot(bool)
    def update(self, state):
        if state:
            self.button.setText(self.text[0])
            self.button.setStyleSheet('background-color: green')
        else:
            self.button.setText(self.text[-1])
            self.button.setStyleSheet('background-color: red')


class Window(QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        # set the layout
        layout = QVBoxLayout(self)
        but = ButtonCtrl(layout, "Test")
        #self.but = ButtonCtrl(layout, "Test")
        btn = CustomButton()
        layout.addWidget(btn)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    main = Window()
    main.show()
    sys.exit(app.exec_())

Я настроил две кнопки с именами CustomButton(QPushButton) и ButtonCtrl(QObject), и я протестировал слот в главном окне, однако Слот фонового обновления работает для CustomButton(QPushbutton) и не работает для ButtonCtrl(QObject), функция слота даже не вызывается.

Однако, если я изменю элемент кнопки ButtonCtrl(QObject) с QPushButton на мой CustomButton(QPushButton), то в главном окне он будет работать нормально. Кроме того, если but в главном окне становится членом класса главного окна, установив self.but=ButtonCtrl(layout, "Test"), он также будет работать.

Я не нашел прямого ответа на него в документации Qt, которая объясняет что

Сигналы излучаются объектом, когда его внутреннее состояние каким-то образом изменилось, что может быть интересно клиенту или владельцу объекта. Сигналы являются общедоступными c функциями доступа и могут быть отправлены откуда угодно, но мы рекомендуем излучать их только из класса, который определяет сигнал и его подклассы.

Я не уверен, что время жизни but вызывает этот эффект, надеюсь получить ответ, спасибо.

1 Ответ

1 голос
/ 17 июня 2020

Проблема проста: объект класса ButtonCtrl имеет локальную область видимости, поэтому он будет уничтожен, и почему то же самое не происходит с объектом класса CustomButton? Ну, поскольку владельцем QWidget является его родительский элемент, а родительским элементом этой кнопки является окно, вместо этого объект ButtonCtrl его не имеет. В этом случае решение состоит в том, чтобы продлить жизненный цикл переменной, а в случае QObject есть несколько вариантов:

  • сделать переменную-член класса,
  • Поместить в контейнере с более длинным жизненным циклом, или
  • устанавливает sh родительский объект QObject с более длительным жизненным циклом.

Использование третьей альтернативы означает просто изменение на:

class ButtonCtrl(QObject):
    def __init__(self,  parent=None, label=''):
        super().__init__(<b>parent</b>)
        # ...

Первый вариант - это тот, который прокомментирован в вашем коде:

self.but = ButtonCtrl(layout, "Test")

, а второй аналогичен:

self.container = list()
but = ButtonCtrl(layout, "Test")
self.container.append(but)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...