从不同线程调用 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::QueuedConnectionQt::BlockingQueuedConnection 连接它们(connect 函数的第五个参数,对于 GUI 更新,Qt::QueuedConnection 可能更可取,因为它不会阻止您线程)。
  • 从您以前执行 setPos( newPos ) 的线程中发出 signalSetPos( newPos )。然后,doSetPos 将从主线程执行(如果您使用 [=17=,稍后使用,如果您使用 Qt::BlockingQueuedConnection,则立即执行)。

检查此 post 以获取有关从线程发出信号的更多信息: Qt - emit a signal from a c++ thread