发送自定义 PyQt 信号?

发布于 2024-08-27 16:20:27 字数 1228 浏览 3 评论 0原文

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

  1. 主/GUI 线程。

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

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

我假设我应该使用信号/槽系统将“状态”Python 列表从 Twitter 线程传输到主/GUI 线程。所以,我的问题有两个:

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

  2. 如何在主/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)

然后,在 Twitter 线程中,我执行以下操作:

self.emit(SIGNAL("newStatuses (statuses)"), statuses)

当这一行是调用后,我收到以下消息:

QObject::connect: Cannot queue arguments of type 'statuses'
(Make sure 'statuses' is registered using qRegisterMetaType().)

我搜索了 qRegisterMetaType(),但没有找到任何我能理解的与 Python 相关的内容。

I'm practicing PyQt and (Q)threads by making a simple Twitter client. I have two Qthreads.

  1. Main/GUI thread.

  2. Twitter fetch thread - fetches data from Twitter every X minutes.

So, every X minutes my Twitter thread downloads a new set of status updates (a Python list). I want to hand this list over to the Main/GUI thread, so that it can update the window with these statuses.

I'm assuming that I should be using the signal / slot system to transfer the "statuses" Python list from the Twitter thread, to the Main/GUI thread. So, my question is twofold:

  1. How do I send the statuses from the Twitter thread?

  2. How do I receive them in the Main/GUI thread?

As far as I can tell, PyQt can by default only send PyQt-objects via signals / slots. I think I'm supposed to somehow register a custom signal which I can then send, but the documentation on this that I've found is very unclear to a newbie like me. I have a PyQt book on order, but it won't arrive in another week, and I don't want to wait until then. :-)

I'm using PyQt 4.6-1 on Ubuntu

Update:

This is an excert from the code that doesn't work. First, I try to "connect" the signal ("newStatuses", a name I just made up) to the function self.update_tweet_list in the Main/GUI thread:

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

Then, in the Twitter thread, I do this:

self.emit(SIGNAL("newStatuses (statuses)"), statuses)

When this line is called, I get the following message:

QObject::connect: Cannot queue arguments of type 'statuses'
(Make sure 'statuses' is registered using qRegisterMetaType().)

I did a search for qRegisterMetaType() but I didn't find anything relating to Python that I could understand.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

听风念你 2024-09-03 16:20:27

你也可以这样做,这更加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)

You can also do this, which is much more pythonic (and readable!).

# 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)
萌无敌 2024-09-03 16:20:27

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

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

...

self.emit(SIGNAL("newStatuses"), statuses)

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

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

....

self.newStatuses.emit(statuses)

When you're using these old-style signals/slots in PyQt, there's actually no need to declare types at all. These should work:

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

...

self.emit(SIGNAL("newStatuses"), statuses)

In this case, PyQt will just create a new signal type for you on the fly when you emit the signal. If you wanted to user the new-style signals, then it would look more like:

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

....

self.newStatuses.emit(statuses)
萌吟 2024-09-03 16:20:27

从这个例子:

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

 int id = QMetaType.type("MyClass");

你可以用Python写下

from PyQt4 import QtCore    
id = QtCore.QMetaType.type('MyClass')

编辑

从评论中提取的答案:

self.emit(SIGNAL("newStatuses(PyQt_PyObject)"), statuses)

From this example:

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

 int id = QMetaType.type("MyClass");

You can write down in Python

from PyQt4 import QtCore    
id = QtCore.QMetaType.type('MyClass')

Edit

The answer extracted from the comment:

self.emit(SIGNAL("newStatuses(PyQt_PyObject)"), statuses)
伊面 2024-09-03 16:20:27

查看这个 问题我不久前问过。有一个代码示例可以帮助您弄清楚需要做什么。

您所说的关于注册信号的内容让我想到了这段代码(来自上述问题):

class ProcessingThread(threading.Thread, QtCore.QObject):
    __pyqtSignals__ = ( "progressUpdated(str)",
                        "resultsReady(str)")

我在示例中传递字符串,但您应该能够将 str 替换为 list< /代码>。

如果事实证明您无法传递可变对象,您可以按照我在示例中的方式处理结果(即在线程中设置一个 results 变量,告诉主线程它们已准备好,并让主线程“捡起它们”)。

更新:

您收到消息QObject::connect:无法对类型为“statuses”的参数进行排队,因为您需要定义该参数的类型当你发出信号时你就会通过。您要传递的类型是 list 而不是 statuses

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

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

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

self.emit(SIGNAL("newStatuses(list)"), statuses)

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

更新2:

好的,使用list作为类型不正确。来自 PyQt4 帮助参考:

PyQt 信号和 Qt 信号

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

QtCore.SIGNAL("完成(int)")

正常传递返回值
QtCore.QObject.connect()
方法。

PyQt 允许定义新信号
动态地。发出的行为
PyQt 信号隐式定义了它。
PyQt v4 信号也被引用
使用QtCore.SIGNAL()
功能。

PyQt_PyObject 信号参数类型

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

QtCore.SIGNAL("完成(PyQt_PyObject)")

虽然这通常用于
传递列表等对象
字典作为信号参数,它
可用于任何 Python 类型。它是
通过时的优势,例如,
一个整数是正常的
从 Python 对象到
C++ 整数和返回都不是
必填。

对象的引用计数
正在通过并维持
自动地。没有必要
信号的发射器保持
调用后对对象的引用
QtCore.QObject.emit(),即使
连接已排队。

Check out this question I asked a while back. There is a code example that might help you figure out what you need to do.

What you said about registering your signal makes me think of this code (from the aforementioned question):

class ProcessingThread(threading.Thread, QtCore.QObject):
    __pyqtSignals__ = ( "progressUpdated(str)",
                        "resultsReady(str)")

I'm passing strings in my example, but you should be able to replace str with list.

If it turns out that you can't pass mutable objects, you can handle your results the way I do in my example (i.e. set a results variable in the thread, tell the main thread that they are ready, and have the main thread "pick them up").

Update:

You get the message QObject::connect: Cannot queue arguments of type 'statuses' because you need to define the type of argument that you will pass when you emit your signal. The type you want to pass is list not statuses.

When you connect your signal it should look like this:

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

When you emit your signal it should look like this:

self.emit(SIGNAL("newStatuses(list)"), statuses)

given that statuses is a list. Note that you may want to emit a deep copy of your list depending on your situation.

Update 2:

Ok, using list as the type is not correct. From the PyQt4 help reference:

PyQt Signals and Qt Signals

Qt signals are statically defined as
part of a C++ class. They are
referenced using the
QtCore.SIGNAL() function. This
method takes a single string argument
that is the name of the signal and its
C++ signature. For example::

QtCore.SIGNAL("finished(int)")

The returned value is normally passed
to the QtCore.QObject.connect()
method.

PyQt allows new signals to be defined
dynamically. The act of emitting a
PyQt signal implicitly defines it.
PyQt v4 signals are also referenced
using the QtCore.SIGNAL()
function.

The PyQt_PyObject Signal Argument Type

It is possible to pass any Python
object as a signal argument by
specifying PyQt_PyObject as the
type of the argument in the signature.
For example::

QtCore.SIGNAL("finished(PyQt_PyObject)")

While this would normally be used for
passing objects like lists and
dictionaries as signal arguments, it
can be used for any Python type. Its
advantage when passing, for example,
an integer is that the normal
conversions from a Python object to a
C++ integer and back again are not
required.

The reference count of the object
being passed is maintained
automatically. There is no need for
the emitter of a signal to keep a
reference to the object after the call
to QtCore.QObject.emit(), even if
a connection is queued.

甜扑 2024-09-03 16:20:27

(Py)Qt 信号和槽跨线程工作与在单线程中一样。所以没有什么特别需要设置的:

在主线程中定义一个槽(方法),并将线程的信号连接到这个槽(连接也应该在主线程中完成)。然后,在线程中,当您想要时,只需发出信号即可工作。 这是关于在 PyQt 中使用带有线程的信号和槽的教程

我建议您先在一个小玩具示例上尝试一下,然后再转向您的应用程序。

(Py)Qt signals and slots work cross-threads just the same as in a single thread. So there's nothing really special to set up:

Define a slot (method) in the main thread, and connect the thread's signal to this slot (the connection shall be also done in the main thread). Then, in the thread, when you want to, just emit the signal and it should work. Here's a tutorial on using signals and slots with threading in PyQt.

I recommend you to try it on a small toy example first, before moving to your application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文