从不同线程调用 setPos 时 QGraphicsItem 消失
QGraphicsItem disappears when calling setPos from a different thread
我在 QGraphicsView
上有两种类型的 QGraphicsItem
,这两种类型中的一种在场景中就像 z-index 为 1 的网格,另一种是蚂蚁,在顶部其中 z-index 为 2。启动程序时,我将所有蚂蚁设置为位置 0,0 并将它们添加到场景中。但是后来我开始通过调用 setPos()
将这些蚂蚁从另一个线程中移走 - 然后我的电脑吃掉了蚂蚁!他们消失在他们原来的位置,但不会出现在他们的新位置。新位置在场景内部
这里是 Ant
class 的代码(继承 QGraphicsItem
):
#include "ant.h"
#include "constants.h"
#include <QPainter>
Ant::Ant()
{
setZValue(2);
}
QRectF Ant::boundingRect() const
{
return QRect(QPoint(0,0), G_FIELD_RECT_SIZE);
}
void Ant::paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget)
{
Q_UNUSED(item)
Q_UNUSED(widget)
QBrush b = painter->brush();
if (food())
painter->setBrush(Qt::blue);
else
painter->setBrush(Qt::black);
painter->drawEllipse(2,3, G_FIELD_RECT_WIDTH - 4, G_FIELD_RECT_HEIGHT - 6);
painter->setBrush(b);
}
经过更多测试后,我发现只要我从 Qt 事件线程调用 setPos
一切正常。一旦我在自定义线程中调用它,蚂蚁就会消失。知道我该如何解决这个问题吗?
你必须回到主线程来做setPos
。正如 ddriver 评论的那样,您不应该从线程修改 GUI(这样做时通常会收到 qDebug
消息,您在调试器中没有收到任何消息吗 window?)。
您只需要:
- 向您的
Ant
class 添加一个新信号(例如 signalSetPos( QPoint pos )
)
- 向您的
Ant
class 添加一个新插槽(如 doSetPos( QPoint pos )
)。此插槽实现仅调用 setPos(pos)
.
- 使用
Qt::QueuedConnection
或 Qt::BlockingQueuedConnection
连接它们(connect
函数的第五个参数,对于 GUI 更新,Qt::QueuedConnection
可能更可取,因为它不会阻止您线程)。
- 从您以前执行
setPos( newPos )
的线程中发出 signalSetPos( newPos )
。然后,doSetPos
将从主线程执行(如果您使用 [=17=,稍后使用,如果您使用 Qt::BlockingQueuedConnection
,则立即执行)。
检查此 post 以获取有关从线程发出信号的更多信息:
Qt - emit a signal from a c++ thread
我在 QGraphicsView
上有两种类型的 QGraphicsItem
,这两种类型中的一种在场景中就像 z-index 为 1 的网格,另一种是蚂蚁,在顶部其中 z-index 为 2。启动程序时,我将所有蚂蚁设置为位置 0,0 并将它们添加到场景中。但是后来我开始通过调用 setPos()
将这些蚂蚁从另一个线程中移走 - 然后我的电脑吃掉了蚂蚁!他们消失在他们原来的位置,但不会出现在他们的新位置。新位置在场景内部
这里是 Ant
class 的代码(继承 QGraphicsItem
):
#include "ant.h"
#include "constants.h"
#include <QPainter>
Ant::Ant()
{
setZValue(2);
}
QRectF Ant::boundingRect() const
{
return QRect(QPoint(0,0), G_FIELD_RECT_SIZE);
}
void Ant::paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget)
{
Q_UNUSED(item)
Q_UNUSED(widget)
QBrush b = painter->brush();
if (food())
painter->setBrush(Qt::blue);
else
painter->setBrush(Qt::black);
painter->drawEllipse(2,3, G_FIELD_RECT_WIDTH - 4, G_FIELD_RECT_HEIGHT - 6);
painter->setBrush(b);
}
经过更多测试后,我发现只要我从 Qt 事件线程调用 setPos
一切正常。一旦我在自定义线程中调用它,蚂蚁就会消失。知道我该如何解决这个问题吗?
你必须回到主线程来做setPos
。正如 ddriver 评论的那样,您不应该从线程修改 GUI(这样做时通常会收到 qDebug
消息,您在调试器中没有收到任何消息吗 window?)。
您只需要:
- 向您的
Ant
class 添加一个新信号(例如signalSetPos( QPoint pos )
) - 向您的
Ant
class 添加一个新插槽(如doSetPos( QPoint pos )
)。此插槽实现仅调用setPos(pos)
. - 使用
Qt::QueuedConnection
或Qt::BlockingQueuedConnection
连接它们(connect
函数的第五个参数,对于 GUI 更新,Qt::QueuedConnection
可能更可取,因为它不会阻止您线程)。 - 从您以前执行
setPos( newPos )
的线程中发出signalSetPos( newPos )
。然后,doSetPos
将从主线程执行(如果您使用 [=17=,稍后使用,如果您使用Qt::BlockingQueuedConnection
,则立即执行)。
检查此 post 以获取有关从线程发出信号的更多信息: Qt - emit a signal from a c++ thread