【问题标题】:PySide QtCore.Slot decorator does not work with self.sender() inside a methodPySide QtCore.Slot 装饰器不适用于方法中的 self.sender()
【发布时间】:2013-08-03 15:39:56
【问题描述】:

我在使用 PySide Slot 装饰器时遇到了这种奇怪的情况。如果我使用 QtCore.Slot 装饰我的方法并且如果我尝试访问方法内部的 self.sender(),我会得到 None。如果我删除 QtCore.Slot() 装饰器。我正确地得到了发件人。这是一个最小的例子。

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class Worker(QObject):
    def init(self):
        print "worker is ready."

    @Slot()
    def work(self):
        print "i am tired, %s" % self.sender()

app = QApplication(sys.argv)
button = QPushButton("Kick!")
button.show()

worker = Worker()
thread = QThread()
worker.moveToThread(thread)
thread.started.connect(worker.init)
button.clicked.connect(worker.work)
# app.connect(button, SIGNAL("clicked()"), worker, SLOT("work()"))
thread.start()

app.exec_()
sys.exit()

但是,如果我将新样式连接更改为旧方式,如注释行所示。

它有效。有人可以解释这种行为吗?非常感谢。

【问题讨论】:

    标签: pyside sender


    【解决方案1】:

    问题在于接收信号的对象(您的 Worker 类)存在于另一个线程中。

    来自 Qt 文档:

    QObject * QObject::sender () const [受保护] 如果在由信号激活的槽中调用,则返回指向发送信号的对象的指针;否则返回 0。该指针仅在从该对象的线程上下文调用该函数的槽执行期间有效。

    如果发送者被销毁,或者槽与发送者的信号断开,则此函数返回的指针无效。

    警告:此功能违反了面向对象的模块化原则。但是,当多个信号连接到单个插槽时,访问发送器可能会很有用。

    警告:如上所述,当插槽通过 Qt::DirectConnection 从与此对象的线程不同的线程调用时,此函数的返回值是无效的 >。请勿在此类场景中使用此功能。

    如果您不将对象移动到另一个线程,它可以工作(示例在 python3 中,但在更改打印行后它将在 python 2 中工作):

    import sys
    from PySide.QtCore import *
    from PySide.QtGui import *
    
    class Worker(QObject):
        def init(self):
            print("worker is ready.")
    
        @Slot()
        def work(self):
            derp = self.sender()
            print ("i am tired, {}".format(derp))
            derp.setText("It works!")
    
    app = QApplication(sys.argv)
    button = QPushButton("Kick!")
    button.show()
    
    worker = Worker()
    button.clicked.connect(worker.work)
    
    app.exec_()
    sys.exit()
    

    【讨论】:

    • 抱歉,因为我正在度假,所以回复晚了。你说的对。我不应该从不同的线程调用。但是,我仍然想知道新式和旧式的区别。我认为它们是等价的,但实际上并非如此。也许这是无证行为?
    • 嗯,它们是等价的(据我所知)。唯一的区别是,新样式更加 Pythonic。旧的方法是它是如何在 C++ 中完成的。来源:qt-project.org/wiki/Signals_and_Slots_in_PySide
    • 是的。这就是我在阅读 signal&slot 文档时的想法。就我而言,我必须使用线程(用于长时间的后台处理),而我目前的解决方案是只使用旧式连接。我对我的魔法代码感到难过......请注意,在我的情况下,删除 Slot 装饰器或使用旧式连接都有效。
    • @Angle 将新/旧样式连接放在一边。你知道为什么移除 Slot 装饰器也有效吗?我的猜测是,没有插槽装饰器,它只是一个 Python 方法。该方法在 sender() 的线程上下文中被调用(我有点不确定)。但在这方面,它是使用 DirectConnection 的代名词,不是吗?警告 2 表示这也不是无效的。
    • 从 SO (stackoverflow.com/questions/14421897/…) 的另一个答案看来,它似乎只会提高速度/内存,并使 C++ 库感到高兴。所以,差别不大。为什么不使用插槽装饰器时会起作用?嗯,这是个好问题。不知道。使用@slot 时可能是“C++ 签名”。有趣的是,所有其他连接类型也不起作用。我测试了一切,在所有情况下我都得到了 None
    猜你喜欢
    • 1970-01-01
    • 2013-02-14
    • 2018-12-06
    • 2020-01-11
    • 2021-07-05
    • 2016-06-30
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多