发送自定义PyQt信号?

Enf*_*ors 28 python pyqt pyqt4 qthread

我正在通过制作一个简单的Twitter客户端来练习PyQt和(Q)线程.我有两个Qthreads.

  1. 主/ GUI线程.

  2. Twitter获取线程 - 每隔X分钟从Twitter获取数据.

因此,每隔X分钟我的Twitter线程就会下载一组新的状态更新(Python列表).我想将此列表交给Main/GUI线程,以便它可以使用这些状态更新窗口.

我假设我应该使用信号/插槽系统将"状态"Python列表从Twitter线程传输到Main/GUI线程.所以,我的问题是双重的:

  1. 如何从Twitter线程发送状态?

  2. 如何在Main/GUI线程中收到它们?

据我所知,PyQt默认只能通过信号/插槽发送PyQt对象.我想我应该以某种方式注册一个我可以发送的自定义信号,但我发现的这个文档对于像我这样的新手来说是非常不清楚的.我订购了一本PyQt书,但它不会在另一周到来,我不想等到那时.:-)

我在Ubuntu上使用PyQt 4.6-1

更新:

这是一个不起作用的代码.首先,我尝试将信号("newStatuses",我刚刚编写的名称)"连接"到Main/GUI线程中的函数self.update_tweet_list:

QtCore.QObject.connect(self.twit_in,
                       QtCore.SIGNAL("newStatuses (statuses)"),
                       self.update_tweet_list)
Run Code Online (Sandbox Code Playgroud)

然后,在Twitter主题中,我这样做:

self.emit(SIGNAL("newStatuses (statuses)"), statuses)
Run Code Online (Sandbox Code Playgroud)

调用此行时,我收到以下消息:

QObject::connect: Cannot queue arguments of type 'statuses'
(Make sure 'statuses' is registered using qRegisterMetaType().)
Run Code Online (Sandbox Code Playgroud)

我搜索了qRegisterMetaType(),但是我找不到任何与Python有关的东西,我能理解.

Mar*_*ser 26

你也可以这样做,这更加pythonic(和可读!).

# create a signal equivalent to "void someSignal(int, QWidget)"
someSignal = QtCore.pyqtSignal(int, QtGui.QWidget)

# define a slot with the same signature
@QtCore.pyqtSlot(int, QtGui.QWidget)
def someSlot(status, source):
    pass

# connect the signal to the slot
self.someSignal.connect(self.someSlot)
Run Code Online (Sandbox Code Playgroud)

  • OP的问题与Qt想要信号参数的类型信息有关; 具体来说,他不知道如何让Qt接受Python中定义的类型.新方式的方法是"someSignal = QtCore.pyqtSignal(object)".有可能获得更强的打字方式,但它们可能涉及更多打字:-) (2认同)

tgr*_*ray 7

看看这个问题,我问了一会儿.有一个代码示例可以帮助您弄清楚您需要做什么.

您对注册信号的说法让我想到了这段代码(来自上述问题):

class ProcessingThread(threading.Thread, QtCore.QObject):
    __pyqtSignals__ = ( "progressUpdated(str)",
                        "resultsReady(str)")
Run Code Online (Sandbox Code Playgroud)

我经过串在我的例子,但你应该能够取代strlist.

如果事实证明你无法传递可变对象,你可以像我在我的例子中那样处理你的结果(即results在线程中设置一个变量,告诉主线程他们已经准备好了,并且让主线程"选择"他们了").

更新:

您收到消息QObject::connect: Cannot queue arguments of type 'statuses'是因为您需要定义在发出信号时将传递的参数类型.您要传递的类型list不是statuses.

连接信号时,它应如下所示:

QtCore.QObject.connect(self.twit_in,
                       QtCore.SIGNAL("newStatuses(list)"),
                       self.update_tweet_list)
Run Code Online (Sandbox Code Playgroud)

当您发出信号时,它应如下所示:

self.emit(SIGNAL("newStatuses(list)"), statuses)
Run Code Online (Sandbox Code Playgroud)

鉴于这statuses是一个清单.请注意,根据您的具体情况,您可能希望发出列表的深层副本.

更新2:

好的,使用list类型不正确.从PyQt4帮助参考:

PyQt信号和Qt信号

Qt信号被静态定义为C++类的一部分.使用该QtCore.SIGNAL()函数引用它们 .此方法采用单个字符串参数,该参数是信号的名称及其C++签名.例如::

QtCore.SIGNAL("finished(int)")
Run Code Online (Sandbox Code Playgroud)

返回的值通常传递给QtCore.QObject.connect() 方法.

PyQt允许动态定义新信号.发出PyQt信号的行为隐含地定义了它.PyQt v4信号也使用该QtCore.SIGNAL() 函数引用.

PyQt_PyObject信号参数类型

通过指定PyQt_PyObject签名中的参数类型,可以将任何Python对象作为信号参数传递.例如::

QtCore.SIGNAL("finished(PyQt_PyObject)")
Run Code Online (Sandbox Code Playgroud)

虽然这通常用于将列表和字典之类的对象作为信号参数传递,但它可以用于任何Python类型.传递一个整数时的优点是不需要从Python对象到C++整数再返回的正常转换.

传递的对象的引用计数自动维护.QtCore.QObject.emit()即使连接排队,也不需要信号的发射器在调用之后保持对对象的引用.


小智 7

从这个例子:

http://doc.qt.digia.com/4.5/qmetatype.html

 int id = QMetaType.type("MyClass");
Run Code Online (Sandbox Code Playgroud)

你可以用Python写下来

from PyQt4 import QtCore    
id = QtCore.QMetaType.type('MyClass')
Run Code Online (Sandbox Code Playgroud)

编辑

从评论中提取的答案:

self.emit(SIGNAL("newStatuses(PyQt_PyObject)"), statuses)
Run Code Online (Sandbox Code Playgroud)

  • 是的,但在谷歌搜索引导我到这个:http://blog.qgis.org/node/102基于这篇文章你可以写:self.emit(SIGNAL("newStatuses(PyQt_PyObject)"),状态)我没有不要试试,所以也许试一试...... (2认同)

Luk*_*uke 6

当您在PyQt中使用这些旧式信号/插槽时,实际上根本不需要声明类型.这些应该工作:

QtCore.QObject.connect(self.twit_in,
                   QtCore.SIGNAL("newStatuses"),
                   self.update_tweet_list)

...

self.emit(SIGNAL("newStatuses"), statuses)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,当你发出信号时,PyQt会为你动态创建一个新的信号类型.如果你想使用新式信号,那么它看起来更像是:

class TwitterThread(QThread):
    newStatuses = pyqtSignal(object)

....

self.newStatuses.emit(statuses)
Run Code Online (Sandbox Code Playgroud)