2013-01-09 107 views
1

我想连接一个VTK回调到Qt插槽,所以当回调发生时,插槽将被触发。连接一个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(); 
} 

这种运作良好,一旦云渲染开始时,点云 - 打印loadCallback开始打印并w当渲染结束并显示云时,消息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-> addPointCloud

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

好的, 我再次检查了代码,发现了一些新的东西。一些同事在load()方法中添加QThread来平滑事情,但忘记记录/说明那里有QThread

在点云::负载()

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()方法,因为我的方法结束前断开回调/槽,一旦云计算正在rendererd该连接ISN”再也没有了!

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