将信号连接到插槽会产生 (nullptr)::slot() 错误

Connecting a signal to slot yields (nullptr)::slot() error

我想将来自自定义 QWidget class (WidgetClass) 的信号连接到 DerivedController 的插槽。 我在实例化两个 classes.

后尝试连接信号

但是,我在 connect() 语句中收到以下错误:

QObject::connect: Cannot connect WidgetClass::mySignal(double) to (nullptr)::mySlot(double)

我不太清楚为什么会这样。如果我理解正确,您只能将信号连接到 classes 实例之间的槽。 下面是我正在编写的伪实现(它在 ipython 中产生相同的错误):

from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
from PyQt5.QtWidgets import QApplication, QWidget

class BaseController():
    def __init__(self, widget1, widget2):
        self.widget1 = widget1
        self.widget2 = widget2

    #@pyqtSlot(float)
    def mySlot(self, value):
        print(f"BaseClass got {value}.")


class DerivedController(BaseController):
    def __init__(self, widget1, widget2):
        super().__init__(widget1, widget2)

    @pyqtSlot(float)
    def mySlot(self, value):
        #super().mySlot(value)
        print(f"Derived class got {value}!")

    def _setupConnections(self):
        self.widget1.mySignal.connect(
            self.mySlot)
        self.widget2.mySignal.connect(
            self.mySlot)

class WidgetClass(QWidget):
    mySignal = pyqtSignal(float)

    def emitSignal(self):
        self.mySignal.emit(1.8)

def myfunc():
    w1 = WidgetClass()
    w2 = WidgetClass()
    controller = DerivedController(w1, w2)
    controller._setupConnections()
    controller.widget1.emitSignal()

def main():
    app = QApplication(["test"])
    return app.exec(myfunc())

if __name__ == "__main__":
    main()

我发现以下部分是错误的:

self.widget1.mySignal.connect(
    self.mySlot)
self.widget2.mySignal.connect(
    self.mySlot)

应该重写为:

self.widget1.mySignal.connect(
    DerivedController.mySlot)
self.widget2.mySignal.connect(
    DerivedController.mySlot)

这似乎解决了问题。 我认为这是因为我们没有绑定到实例的插槽,而是 class 本身的插槽,就像声明为 class 定义的一部分的信号一样,而不是 class 实例化(我希望这是有道理的)。

OP提出的解决方案不正确,因为错误原因不同:

如果你继承自class P,那么你必须调用class P的构造函数,在你的情况下,继承自QObject的BaseController不会调用QObject的构造函数。

综合以上问题的报错信息不再获取,但还有其他问题:

  • 一个函数的作用域是有限的,在该函数内创建的对象在函数执行时会被销毁,在这种情况下"controller"被销毁可能会导致问题。

  • 另一方面,QApplication exec() 方法不应接收任何参数。

综合以上,解决方案是:

from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
from PyQt5.QtWidgets import QApplication, QWidget


class BaseController(QObject):
    def __init__(self, widget1, widget2):
        <b>super().__init__()</b>
        self.widget1 = widget1
        self.widget2 = widget2

    # @pyqtSlot(float)
    def mySlot(self, value):
        print(f"BaseClass got {value}.")


class DerivedController(BaseController):
    def __init__(self, widget1, widget2):
        super().__init__(widget1, widget2)

    @pyqtSlot(float)
    def mySlot(self, value):
        # super().mySlot(value)
        print(f"Derived class got {value}!")

    def _setupConnections(self):
        self.widget1.mySignal.connect(self.mySlot)
        self.widget2.mySignal.connect(self.mySlot)


class WidgetClass(QWidget):
    mySignal = pyqtSignal(float)

    def emitSignal(self):
        self.mySignal.emit(1.8)


def myfunc():
    w1 = WidgetClass()
    w2 = WidgetClass()
    controller = DerivedController(w1, w2)
    controller._setupConnections()
    controller.widget1.emitSignal()

    <b>return controller</b>


def main():
    app = QApplication(["test"])
    <b>controller = myfunc()
    return app.exec()</b>


if __name__ == "__main__":
    main()

另一方面,OP 在其回答中指出:我认为这是因为我们没有绑定到实例的插槽,而是 class 本身的插槽为false,对象之间有联系。

您在 BaseController

中忘记了 super().__init__() 调用