自定义类中的信号和插槽(包括PyQt QWidget)不工作

2024-09-30 05:17:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我在自定义包含QPushButtonQLabel的类时遇到一些问题,我只想设置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文档中找到直接的答案来解释这一点

Signals are emitted by an object when its internal state has changed in some way that might be interesting to the object's client or owner. Signals are public access functions and can be emitted from anywhere, but we recommend to only emit them from the class that defines the signal and its subclasses.

我不确定是否是but的寿命造成了这种影响,希望能得到一个答案,谢谢


Tags: fromimportselftrueinitdefbuttonlabel
1条回答
网友
1楼 · 发布于 2024-09-30 05:17:39

问题很简单:ButtonCtrl类对象有一个局部作用域,因此它将被销毁,为什么CustomButton类对象不会发生同样的情况?好吧,因为QWidget的所有权有它的父对象,而该按钮的父对象是窗口,而ButtonCtrl对象没有它。在这种情况下,解决方案是延长变量的生命周期,对于QObject,有几个选项:

  • 使类成员变为变量
  • 将其放置在寿命周期较长的容器中,或
  • 建立具有较长生命周期的QObject父对象

使用第三种方法只是将其更改为:

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

第一个选项是在代码中注释的选项:

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

第二个是类似的:

self.container = list()
but = ButtonCtrl(layout, "Test")
self.container.append(but)

相关问题 更多 >

    热门问题