将VTK回调连接到Qt插槽

时间:2013-01-09 11:52:10

标签: callback qt4 signals-slots vtk point-cloud-library

我正在尝试将VTK回调连接到Qt广告位,因此在回调发生时会触发广告位。

我正在使用QVTKWidget呈现已添加到PCLVisualizer的点云(来自点云库,PCL)。

让我们展示一些代码:

PointCloud.h

class PointCloud: public QObject {
Q_OBJECT
  private:
    static void loadStartCallback(
      vtkObject *caller,
      unsigned long eventId,
      void *clientData,
      void *callData
    );

    static void loadEndCallback(
      vtkObject *caller,
      unsigned long eventId,
      void *clientData,
      void *callData
    );
    void load(void);
    // more funcs and methods

  private:
   QVTKWidget* widget;
   pcl::visualization::PCLVisualizer* visualizer;
   unsinged long observerStartTag;
   unsinged long observerEndTag;
   // more attributes
}

PointCloud.cpp

  void PointCloud::loadStartCallback(
    vtkObject* caller,
    unsigned long eventId,
    void* clientData,
    void* callData
  ) {
    qDebug() << "\t\tPointCloud - loadCallback started\n";
    if(clientData) {
      PointCloud* self = reinterpret_cast<PointCloud*>( clientData );
      self->widget->GetRenderWindow()->RemoveObserver(self->observerStartTag);
  }

  void PointCloud::loadEndCallback(
    vtkObject* caller,
    unsigned long eventId,
    void* clientData,
    void* callData
  ) {
    qDebug() << "\t\tPointCloud - loadCallback ended\n";
    if(clientData) {
      PointCloud* self = reinterpret_cast<PointCloud*>( clientData );
      self->widget->GetRenderWindow()->RemoveObserver(self->observerEndTag);
    }
  }

 void load(void) {
   vtkSmartPointer<vtkRenderWindow> renderWindow = visualizer->getRenderWindow();

   vtkSmartPointer<vtkCallbackCommand> startCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    startCallback->SetCallback( loadStartCallback );
    startCallback->SetClientData(this);
    observerStartTag = renderWindow->AddObserver(vtkCommand::StartEvent, startCallback );

    vtkSmartPointer<vtkCallbackCommand> endCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    endCallback->SetCallback( loadEndCallback );
    endCallback->SetClientData(this);
    observerEndTag = renderWindow->AddObserver(vtkCommand::EndEvent, endCallback );

    // more processing. local_cloud is already populated 
    // and functional at this point
    widget->SetRenderWindow( renderWindow );
    visualizer->addPointCloud<pcl::PointXYZ>(local_cloud, "local_cloud");
    widget->Show();
    widget->Update();
 }

这很有效,一旦云渲染开始,就会打印 PointCloud - loadCallback started ,当渲染结束并显示云时,消息 PointCloud - loadCallback结束被打印。

现在,除了打印结束消息之外,我还要发布Qt个插槽。我正在尝试使用vtkEventQtSlotConnect类,因为它似乎是将回调连接到插槽的正确选择:

PointCloud.h中的新功能

private slots:
  void test(void);

PointCloud.cpp中的新功能

void PointCloud::test(void) { qDebug() << "\t\tThis is a test\n; }

在调用visualizer-&gt; addPointCloud之前添加到PointCloud :: load()

    vtkEventQtSlotConnect* vtk_qt_connector = vtkEventQtSlotConnect::New();
    vtk_qt_connector->Connect(
        renderWindow,
        vtkCommand::EndEvent,
        this,
        SLOT(test(void)),
        0,
        1.0
    );

    // AFTER widget->Update()
    vtk_qt_connector->Disconnect(); // NO PARAM: disconnects ALL slots
    vtk_qt_connector->Delete();
  } // End of PointCloud::load()

通过这些添加,将打印回调中的消息,但test()插槽中的消息永远不会显示。

知道我做错了什么?

修改

在我看过的VTK回调示例中,vtkRendeWindowInteractor用于管理回调。但是,如果我向其添加回调观察器,则不如直接将它们添加到渲染窗口那样准确。

1 个答案:

答案 0 :(得分:1)

确定, 我再次检查了代码并找到了新的东西。一些同事在QThread方法中添加了load()来平滑事物,但忘记记录/告知那里有QThread

在PointCloud :: load()

 QThread* thread = new QThread;
 ThreadedCloud* tcloud = new ThreadedCloud; // computes internal vars and more
 tcloud->moveToThread(thread);

 connect(thread, SIGNAL(started()), tcloud, SLOT(read()), Qt::QueuedConnection );
 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()), Qt::QueuedConnection );
 connect(tcloud, SIGNAL(cloudIsLoaded()), this, SLOT(addCloudToViewer()), Qt::QueuedConnection );
 connect(tcloud, SIGNAL(cloudIsLoaded()), thread, SLOT(quit()), Qt::QueuedConnection );
 connect(tcloud, SIGNAL(cloudIsLoaded()), tcloud, SLOT(deleteLater()), Qt::QueuedConnection );
 connect(tcloud, SIGNAL(cloudIsNotLoaded(std::string)), this, SLOT(errorLoadingCloud(std::string)), Qt::QueuedConnection );
 thread->start();

cloudIsLoaded()是线程完成任何必须执行的操作后发出的信号,我们已准备好将云添加到PCLVisualizer并进行渲染。这是在addCloudToViewer中完成的。

这里的关键因素是,一旦线程启动,控制流就会退出load()方法,因为我在方法结束之前断开了回调/插槽,一旦云被渲染出来连接不再存在了!

因此,解决方案是在vtk_qt_connector方法中移动addCloudToViewer并执行回调/插槽连接。