- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在让派生类在 PySide 中正确接收信号时遇到问题。我在主线程(GUI 或命令行应用程序)的两个独立线程上使用发射器和接收器。线程是 QThread 对象。发送器和接收器在使用 QObject.moveToThread() 创建后立即移动到它们的线程。如果接收器直接派生自 QObject,则一切正常,并且接收器在其线程内接收。但是,如果接收器是从派生自 QObject 的基类派生的,则接收器仍会接收到信号,但会在错误的线程(主线程)上接收信号。
示例(一些信号调试代码改编自 PyQt & unittest - Testing signal and slots ):
#!/usr/bin/env python3
# weigh/bugtest_qt_signal_derived.py
import logging
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
import sys
import threading
import time
from PySide import QtCore
from PySide.QtCore import (
QCoreApplication,
QObject,
QThread,
Signal,
Slot,
)
_oldEmit = QtCore.QObject.emit # normal method
def debug_emit(self, *args):
logger.debug("EMIT: thread name={}, emit args={}".format(
threading.current_thread().name,
repr(args),
))
_oldEmit(self, *args)
QtCore.QObject.emit = debug_emit
def report(msg):
logger.info("{} [{}]".format(msg, threading.current_thread().name))
class Transmitter(QObject):
transmit = Signal()
finished = Signal()
def start(self):
count = 3
logger.info("Starting transmitter")
while count > 0:
time.sleep(1) # seconds
report("transmitting, count={}".format(count))
self.transmit.emit()
count -= 1
logger.info("Stopping transmitter")
self.finished.emit()
class Base(QObject):
def __init__(self, parent=None):
super().__init__(parent=parent)
@Slot()
def start(self):
report("Starting receiver")
@Slot()
def receive(self):
report("receive: BASE")
class Derived(Base):
def __init__(self, parent=None):
super().__init__(parent=parent)
@Slot()
def receive(self):
report("receive: DERIVED")
USE_DERIVED = True
if __name__ == '__main__':
logging.basicConfig()
logger.setLevel(logging.DEBUG)
# Objects
app = QCoreApplication(sys.argv)
tx_thread = QThread()
transmitter = Transmitter()
transmitter.moveToThread(tx_thread)
rx_thread = QThread()
if USE_DERIVED:
receiver = Derived()
else:
receiver = Base()
receiver.moveToThread(rx_thread)
# Signals: startup
tx_thread.started.connect(transmitter.start)
rx_thread.started.connect(receiver.start)
# ... shutdown
transmitter.finished.connect(tx_thread.quit)
tx_thread.finished.connect(rx_thread.quit)
rx_thread.finished.connect(app.quit)
# ... action
transmitter.transmit.connect(receiver.receive)
# Go
rx_thread.start()
tx_thread.start()
report("Starting app")
app.exec_()
USE_DERIVED = False
的输出:
INFO:__main__:Starting app [MainThread]
INFO:__main__:Starting receiver [Dummy-1]
INFO:__main__:Starting transmitter
INFO:__main__:transmitting, count=3 [Dummy-2]
DEBUG:__main__:EMIT: thread name=Dummy-2, emit args=('2transmit()',)
INFO:__main__:receive: BASE [Dummy-1]
INFO:__main__:transmitting, count=2 [Dummy-2]
DEBUG:__main__:EMIT: thread name=Dummy-2, emit args=('2transmit()',)
INFO:__main__:receive: BASE [Dummy-1]
INFO:__main__:transmitting, count=1 [Dummy-2]
DEBUG:__main__:EMIT: thread name=Dummy-2, emit args=('2transmit()',)
INFO:__main__:Stopping transmitter
DEBUG:__main__:EMIT: thread name=Dummy-2, emit args=('2finished()',)
INFO:__main__:receive: BASE [Dummy-1]
USE_DERIVED = True
的输出:
INFO:__main__:Starting app [MainThread]
INFO:__main__:Starting receiver [MainThread]
INFO:__main__:Starting transmitter
INFO:__main__:transmitting, count=3 [Dummy-1]
DEBUG:__main__:EMIT: thread name=Dummy-1, emit args=('2transmit()',)
INFO:__main__:receive: DERIVED [MainThread]
INFO:__main__:transmitting, count=2 [Dummy-1]
DEBUG:__main__:EMIT: thread name=Dummy-1, emit args=('2transmit()',)
INFO:__main__:receive: DERIVED [MainThread]
INFO:__main__:transmitting, count=1 [Dummy-1]
DEBUG:__main__:EMIT: thread name=Dummy-1, emit args=('2transmit()',)
INFO:__main__:Stopping transmitter
DEBUG:__main__:EMIT: thread name=Dummy-1, emit args=('2finished()',)
INFO:__main__:receive: DERIVED [MainThread]
...区别在于 Base 类在其自己的线程上接收,而 Derived 类在 MainThread 上接收。
有人知道为什么吗?非常感谢!
软件:PySide 版本:1.2.4; QtCore 版本:4.8.6; Ubuntu 14.04; Python 3.4.4。
进一步@101 的评论:
信号覆盖不是失败所必需的。这些派生类也会失败(在错误的线程中被调用的意义上):
class DerivedTwo(Base):
def __init__(self, parent=None):
super().__init__(parent=parent)
class DerivedThree(Base):
def __init__(self, parent=None):
QObject.__init__(self, parent=parent)
由于输出表明派生的接收者对象在错误的线程上启动,我想知道问题是否是派生对象的 QObject.moveToThread()
失败。然而,情况似乎并非如此:
def debug_object(obj):
logger.debug("Object {} belongs to QThread {}".format(obj, obj.thread()))
def debug_thread(thread_name, thread):
logger.debug("{} is QThread {}".format(thread_name, thread))
# ...
tx_thread = QThread()
debug_thread("tx_thread", tx_thread)
transmitter = Transmitter()
debug_object(transmitter)
transmitter.moveToThread(tx_thread)
debug_object(transmitter)
rx_thread = QThread()
debug_thread("rx_thread", rx_thread)
receiver = DerivedTwo()
debug_object(receiver)
receiver.moveToThread(rx_thread)
debug_object(receiver)
给予
DEBUG:__main__:tx_thread is QThread <PySide.QtCore.QThread object at 0x7fc4a3befd08>
DEBUG:__main__:Object <__main__.Transmitter object at 0x7fc4a3bf2648> belongs to QThread <PySide.QtCore.QThread object at 0x7fc4a3bf2688>
DEBUG:__main__:Object <__main__.Transmitter object at 0x7fc4a3bf2648> belongs to QThread <PySide.QtCore.QThread object at 0x7fc4a3befd08>
DEBUG:__main__:rx_thread is QThread <PySide.QtCore.QThread object at 0x7fc4a3bf2708>
DEBUG:__main__:Object <__main__.DerivedTwo object at 0x7fc4a3bf2788> belongs to QThread <PySide.QtCore.QThread object at 0x7fc4a3bf2688>
DEBUG:__main__:Object <__main__.DerivedTwo object at 0x7fc4a3bf2788> belongs to QThread <PySide.QtCore.QThread object at 0x7fc4a3bf2708>
INFO:__main__:Starting app [MainThread]
INFO:__main__:Starting receiver [MainThread]
INFO:__main__:Starting transmitter [Dummy-1]
INFO:__main__:transmitting, count=3 [Dummy-1]
DEBUG:__main__:EMIT: thread name=Dummy-1, emit args=('2transmit()',)
INFO:__main__:receive: BASE [MainThread]
...
这向我表明派生对象在 moveToThread()
期间被正确传输到一个新线程(名义上,用于 Qt 事件处理),但随后在主线程上启动(并接收)以某种方式线程。
附加:它适用于 C++ Qt
标题:
// bugtest_qt_signal_derived.h
#include <QtCore/QCoreApplication>
#include <QtCore/QtDebug> // not QDebug
#include <QtCore/QObject>
#include <QtCore/QString> // works with qDebug where std::string doesn't
#include <QtCore/QThread>
void debug_object(const QString& obj_name, const QObject& obj);
void debug_thread(const QString& thread_name, const QThread& thread);
void report(const QString& msg);
class Transmitter : public QObject
{
Q_OBJECT // enables macros like "signals:", "slots:", "emit"
public:
Transmitter() {}
virtual ~Transmitter() {}
signals:
void transmit();
void finished();
public slots:
void start();
};
class Base : public QObject
{
Q_OBJECT
public:
Base() {}
public slots:
void start();
void receive();
};
class Derived : public Base
{
Q_OBJECT
public:
Derived() {}
public slots:
void receive();
};
来源:
// bugtest_qt_signal_derived.cpp
#include "bugtest_qt_signal_derived.h"
#include <unistd.h> // for sleep()
void debug_object(const QString& obj_name, const QObject& obj)
{
qDebug() << "Object" << obj_name << "belongs to QThread" << obj.thread();
}
void debug_thread(const QString& thread_name, const QThread& thread)
{
qDebug() << thread_name << "is QThread at" << &thread;
}
void report(const QString& msg)
{
qDebug().nospace() << msg << " [" << QThread::currentThreadId() << "]";
}
void Transmitter::start()
{
unsigned int count = 3;
report("Starting transmitter");
while (count > 0) {
sleep(1); // seconds
report(QString("transmitting, count=%1").arg(count));
emit transmit();
count -= 1;
}
report("Stopping transmitter");
emit finished();
}
void Base::start()
{
report("Starting receiver");
}
void Base::receive()
{
report("receive: BASE");
}
void Derived::receive()
{
report("receive: DERIVED");
}
#define USE_DERIVED
int main(int argc, char* argv[])
{
// Objects
QCoreApplication app(argc, argv);
QThread tx_thread;
debug_thread("tx_thread", tx_thread);
Transmitter transmitter;
debug_object("transmitter", transmitter);
transmitter.moveToThread(&tx_thread);
debug_object("transmitter", transmitter);
QThread rx_thread;
debug_thread("rx_thread", rx_thread);
#ifdef USE_DERIVED
Derived receiver;
#else
Base receiver;
#endif
debug_object("receiver", receiver);
receiver.moveToThread(&rx_thread);
debug_object("receiver", receiver);
// Signals: startup
QObject::connect(&tx_thread, SIGNAL(started()),
&transmitter, SLOT(start()));
QObject::connect(&rx_thread, SIGNAL(started()),
&receiver, SLOT(start()));
// ... shutdown
QObject::connect(&transmitter, SIGNAL(finished()),
&tx_thread, SLOT(quit()));
QObject::connect(&tx_thread, SIGNAL(finished()),
&rx_thread, SLOT(quit()));
QObject::connect(&rx_thread, SIGNAL(finished()),
&app, SLOT(quit()));
// ... action
QObject::connect(&transmitter, SIGNAL(transmit()),
&receiver, SLOT(receive()));
// Go
rx_thread.start();
tx_thread.start();
report("Starting app");
return app.exec();
}
输出:
"tx_thread" is QThread at QThread(0x7ffc138c5330)
Object "transmitter" belongs to QThread QThread(0xdae1e0)
Object "transmitter" belongs to QThread QThread(0x7ffc138c5330)
"rx_thread" is QThread at QThread(0x7ffc138c5350)
Object "receiver" belongs to QThread QThread(0xdae1e0)
Object "receiver" belongs to QThread QThread(0x7ffc138c5350)
"Starting app" [0x7f032fb32780]
"Starting transmitter" [0x7f032ae77700]
"Starting receiver" [0x7f032b678700]
"transmitting, count=3" [0x7f032ae77700]
"receive: DERIVED" [0x7f032b678700]
"transmitting, count=2" [0x7f032ae77700]
"receive: DERIVED" [0x7f032b678700]
"transmitting, count=1" [0x7f032ae77700]
"Stopping transmitter" [0x7f032ae77700]
"receive: DERIVED" [0x7f032b678700]
补充:在PyQt中也有效
代码:
#!/usr/bin/env python2
import logging
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
import sys
import threading
import time
from PyQt4.QtCore import (
QCoreApplication,
QObject,
QThread,
pyqtSignal,
pyqtSlot,
)
def debug_object(obj):
logger.debug("Object {} belongs to QThread {}".format(obj, obj.thread()))
def debug_thread(thread_name, thread):
logger.debug("{} is QThread {}".format(thread_name, thread))
def report(msg):
logger.info("{} [{}]".format(msg, threading.current_thread().name))
class Transmitter(QObject):
transmit = pyqtSignal()
finished = pyqtSignal()
def start(self):
count = 3
report("Starting transmitter")
while count > 0:
time.sleep(1) # seconds
report("transmitting, count={}".format(count))
self.transmit.emit()
count -= 1
report("Stopping transmitter")
self.finished.emit()
class Base(QObject):
def __init__(self, parent=None):
super(Base, self).__init__(parent=parent)
@pyqtSlot()
def start(self):
report("Starting receiver")
@pyqtSlot()
def receive(self):
report("receive: BASE")
class Derived(Base):
def __init__(self, parent=None):
super(Derived, self).__init__(parent=parent)
@pyqtSlot()
def receive(self):
report("receive: DERIVED")
USE_DERIVED = True
if __name__ == '__main__':
logging.basicConfig()
logger.setLevel(logging.DEBUG)
# Objects
app = QCoreApplication(sys.argv)
tx_thread = QThread()
debug_thread("tx_thread", tx_thread)
transmitter = Transmitter()
debug_object(transmitter)
transmitter.moveToThread(tx_thread)
debug_object(transmitter)
rx_thread = QThread()
debug_thread("rx_thread", rx_thread)
if USE_DERIVED:
receiver = Derived()
else:
receiver = Base()
debug_object(receiver)
receiver.moveToThread(rx_thread)
debug_object(receiver)
# Signals: startup
tx_thread.started.connect(transmitter.start)
rx_thread.started.connect(receiver.start)
# ... shutdown
transmitter.finished.connect(tx_thread.quit)
tx_thread.finished.connect(rx_thread.quit)
rx_thread.finished.connect(app.quit)
# ... action
transmitter.transmit.connect(receiver.receive)
# Go
rx_thread.start()
tx_thread.start()
report("Starting app")
app.exec_()
输出:
DEBUG:__main__:tx_thread is QThread <PyQt4.QtCore.QThread object at 0x7fd0b7ad0770>
DEBUG:__main__:Object <__main__.Transmitter object at 0x7fd0b7ad0808> belongs to QThread <PyQt4.QtCore.QThread object at 0x7fd0b7ad08a0>
DEBUG:__main__:Object <__main__.Transmitter object at 0x7fd0b7ad0808> belongs to QThread <PyQt4.QtCore.QThread object at 0x7fd0b7ad0770>
DEBUG:__main__:rx_thread is QThread <PyQt4.QtCore.QThread object at 0x7fd0b7ad08a0>
DEBUG:__main__:Object <__main__.Derived object at 0x7fd0b7ad0938> belongs to QThread <PyQt4.QtCore.QThread object at 0x7fd0b7ad09d0>
DEBUG:__main__:Object <__main__.Derived object at 0x7fd0b7ad0938> belongs to QThread <PyQt4.QtCore.QThread object at 0x7fd0b7ad08a0>
INFO:__main__:Starting app [MainThread]
INFO:__main__:Starting transmitter [Dummy-1]
INFO:__main__:Starting receiver [Dummy-2]
INFO:__main__:transmitting, count=3 [Dummy-1]
INFO:__main__:receive: DERIVED [Dummy-2]
INFO:__main__:transmitting, count=2 [Dummy-1]
INFO:__main__:receive: DERIVED [Dummy-2]
INFO:__main__:transmitting, count=1 [Dummy-1]
INFO:__main__:Stopping transmitter [Dummy-1]
INFO:__main__:receive: DERIVED [Dummy-2]
确认@101 在 Python 3 中的发现
如下所述。只需删除所有 @Slot() 装饰器即可正常工作。
所以这似乎是一个与 Slot 装饰器相关的 PySide 错误。
非常感谢!
最佳答案
在 Windows 上使用 Python 2.7.10 和 PySide 1.2.2 我做了一个类似的例子并发现了同样的问题。是的,当连接到派生类时,代码实际上似乎卡在了主线程中(我通过阻塞主线程来检查这一点,以表明监听器不再响应)。这是我使用的最小示例:
from PySide import QtCore, QtGui
import threading, time, sys
class Signaller(QtCore.QObject):
signal = QtCore.Signal()
def send_signals(self):
while True:
self.signal.emit()
time.sleep(1)
class BaseListener(QtCore.QObject):
@QtCore.Slot()
def on_signal(self):
print 'Got signal in', threading.current_thread().name
class DerivedListener(BaseListener):
pass
class App(QtGui.QApplication):
def __init__(self, sys_argv):
super(App, self).__init__(sys_argv)
# self.listener = BaseListener()
self.listener = DerivedListener()
self.listener_thread = QtCore.QThread()
self.listener.moveToThread(self.listener_thread)
self.signaller = Signaller()
self.signaller_thread = QtCore.QThread()
self.signaller.moveToThread(self.signaller_thread)
self.signaller.signal.connect(self.listener.on_signal)
self.signaller_thread.started.connect(self.signaller.send_signals)
self.listener_thread.start()
self.signaller_thread.start()
sys.exit(App(sys.argv).exec_())
我找到了几个解决方法:
@QtCore.Slot
装饰器(无论如何它通常是不必要的)@QtCore.Slot
装饰器添加一个未使用的参数,例如@QtCore.Slot(int)
,但前提是参数实际上没有作为参数传递给方法。也许添加这个虚拟参数实际上会使装饰器无效。所以,是的,似乎无法将已经具有用装饰器定义的插槽的类子类化到线程中。我也很想知道这是为什么。
PySide 错误在这里: https://bugreports.qt.io/browse/PYSIDE-249
关于python - 派生类在 PySide (Qt/PyQt) 的错误线程中接收信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34125065/
我想更新小部件的值,但为了防止无限循环,我需要防止调用此小部件的回调函数 .valueChanged信号。 以下示例完全按预期工作: Qt = PySide class MainWindow(Acto
使用以下代码,在尝试发出信号时出现错误(“PySide.QtCore.Signal”对象没有属性“emit”): #!/usr/bin/env python from PySide import Qt
我是 Python 新手。我同时安装了 Python 2.7 和 Python 3。我刚刚尝试通过 Homebrew 安装 PySide 并收到此消息: PySide package successf
是否可以使用 PySide 中的 Web 类之一加载包含按钮的本地 html/JS 文件,并将这些按钮连接到 PySide 插槽? 最佳答案 您可以使用 QtWebKit 将 QObject 导出到
我一直在寻找一个工作示例,该示例如何在使用 QT 设计器创建的 pyside 中嵌入 matplotlib 图,同时将逻辑保存在单独的文件中。我知道网上有很多例子,但没有一个真正使用 QT 设计器,然
我想我可以通过将\PySide 文件夹附加到我的环境的“搜索路径”来添加 PySide 库,但智能感知似乎没有发现任何东西。不过,它正在使用我的其他图书馆。有什么建议吗? 注意:我已经安装了 PTVS
我正在设计一个 Pyside Qt 应用程序,我想切换 QtCore.Qt.WindowStaysOnTopHint我的主窗口中的窗口标志。使用此代码设置此提示工作正常: self.setWindow
你如何在 PySide 中禁用声子? 我正在尝试使用 QWebpage 并且我不希望 phonon 启动,因为我正在编写的应用程序是服务器端应用程序,并且不需要媒体。我尝试了一些东西,但没有找到任何真
本文为大家分享了pyside pyqt实现鼠标右键菜单功能的具体代码,供大家参考,具体内容如下 在三维软件中使用pyside/pyqt编写gui界面时,为了艺术家使用操作的简洁,以及方便,经常会使
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我试图在 PySide 的单独线程中运行一个长任务,以便主线程可以继续处理 GUI 事件。我已经阅读了执行此操作的正确方法: 将任务封装在 QObject 子类中,其中工作在 run() 方法中完成,
我想知道如何根据最大标签的最大宽度/高度截断QLabel中的文本。 输入的文本可以是任意长度,但是为了保持整洁的布局,我想截断长字符串以填充最大空间(小部件的最大宽度/高度)。 例如。: 'A ve
我有一个界面,屏幕顶部有 4 个按钮,下面有 QFrame。我想根据按下的按钮更改 QFrame 中的布局。例如,如果按下 Button_1 显示一个 TextEdit Widget,如果按下 But
我想制作一个小部件的角。在 PyQt 中,我用样式表解决了这个问题,效果很好。我想在 PySide 中做同样的事情,但由于某些原因它不起作用。 这是我的代码: TitelWidget = QtGui.
我是 python 和 pyside 的新手。我将尝试成功运行以下代码。但现在我希望程序在显示窗口后等待用户无法使用它的定义时间,然后升级状态栏。我会尝试 sleep() 但不知道它必须以正确的方式放
我从 example of Zetcode 开始学习 PySide并尝试编写具有两个窗口的应用程序:“布局 View ”的父级“示意图 View ”,每个窗口都有菜单栏。启动时应该只是原理图窗口,布局
我从 example of Zetcode 开始学习 PySide并尝试编写具有两个窗口的应用程序:“布局 View ”的父级“示意图 View ”,每个窗口都有菜单栏。启动时应该只是原理图窗口,布局
我正在尝试通过 pyside 设置 QGridLayout 小部件的背景图像(位于与应用程序相同的文件夹中),但无济于事我已经查看了有关样式表的所有图、文档和论坛帖子,但仍然我不知道我做错了什么。 f
我有一个带有 5 个按钮的布局,我充当“菜单”,因此您单击一个按钮,会显示一个 View ,单击另一个按钮,会显示另一个 View 。我需要找出单击了哪个按钮,以便我可以根据按下的按钮执行某些操作。类
基本上我想要的是: 在主窗口中显示一个小部件,其中包含打开 QFileDialog 的按钮 选择文件后,包含按钮的小部件应切换到新的小部件,该新小部件会显示一些基于文件内容的可视化效果。 在下面的代码
我是一名优秀的程序员,十分优秀!