2

VTKコールバックをスロットに接続しようとしているQtので、コールバックが発生したときにスロットが起動されます。

(ポイントクラウドライブラリ、PCLから)QVTKWidgetに追加されたポイントクラウドをレンダリングするためにを使用しています。PCLVisualizer

いくつかのコードを示しましょう:

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 startが出力され、レンダリングが終了してクラウドが表示されると、メッセージPointCloud--loadCallbackendedが出力されます。

さて、終了メッセージを印刷するだけでなく、Qtスロットも発射したいと思います。vtkEventQtSlotConnectコールバックをスロットに接続するための正しい選択であると思われるので、私はそのためにクラスを使用しようとしています。

PointCloud.hの新機能

private slots:
  void test(void);

PointCloud.cppの新機能

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

ビジュアライザー->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は、コールバックを管理するためにaが使用されています。ただし、コールバックオブザーバーを追加すると、レンダリングウィンドウに直接追加するほど正確ではありません。

4

1 に答える 1

2

わかりました。コードをもう一度確認して、何か新しいものを見つけました。何人かの同僚は物事をスムーズ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コールバック/スロット接続を行うことでした。

于 2013-01-09T12:25:21.017 に答える