信号到插槽连接:在循环内迭代触发信号

时间:2019-02-27 07:40:25

标签: qt signals-slots qt3d

设置光线投射器

我将QRayCaster添加到我的根实体并将其信号连接到插槽:

void MySceneClass::createRootEntity()
{
    // ...
    // Add ray caster to root entity
    m_rayCaster = new Qt3DRender::QRayCaster(m_rootEntity);
    m_rayCaster->setRunMode(Qt3DRender::QAbstractRayCaster::SingleShot);
    m_rootEntity->addComponent(m_rayCaster);

    // Set up signal to slot connection
    QObject::connect(m_rayCaster, &Qt3DRender::QRayCaster::hitsChanged,
                     this,        &MySceneClass::handleRayCasterHits);
    // ...
}

我在插槽中记录射线投射器的点击次数:

void MySceneClass::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{

    qDebug() << "Ray casting resulted in hits";

}

触发射线投射器

我在循环内迭代触发射线投射器:

void MyOtherClass::triggerRayCaster()
{

    for (int i = 0; i < 100; ++i) {

        m_mySceneClass->castRay(QVector3D(i, i, 50.0f),       // origin
                                QVector3D(0.0f, 0.0f, -1.0f), // direction
                                -1                            // length (-1 means infinite)
                                );

    }

}

问题

问题是,在所有测试中,triggerRayCaster()内的触发器循环仅最后一次迭代handleRayCasterHits()内的插槽捕获并记录。

我不明白为什么。我想念什么吗?

1 个答案:

答案 0 :(得分:1)

要了解为什么会发生这种情况,您需要了解Qt3D的工作原理:

  1. Qt3D执行线程中的所有内容。渲染,逻辑和其他所有东西都有自己的线程,并且并行执行(除非您告诉它不要这样做)。

  2. Qt3D有一个前端(您在代码中使用的内容)和一个后端。前端节点被转换为后端节点。例如,看看backend nodes of the renderer。渲染线程收集所有渲染后端节点,并在渲染阶段执行它们。所有其他线程对其后端节点(逻辑,输入等)执行相同的操作。每当前端节点发生更改时,它们都会通知后端节点,以便它们可以相应地修改其内容或被删除或创建。

这意味着,您在示例代码中所做的就是迅速(因为在微秒内执行了循环)设置了要在射线投射器上投射的射线的方向,但是这不会投射射线还。实际的光线投射发生在处理与您的前端光线投射器节点相对应的后端节点的后端线程执行光线投射时。在for循环执行所需的几微秒内,这永远不会发生。 这就是为什么您需要一个回调函数来获得匹配,而不能简单地投射光线并在下一行代码中获得结果的原因。

解决方案: 您需要做的是从回调函数中投射下一条光线,并在某个位置存储并建立索引,以告诉您何时停止投射新光线,或者您使用间隔为100ms的计时器(对于所有计时器而言,这应该足够Qt3D的线程至少要执行一次,因为它可能以30fps的速度运行),从而触发射线投射。