2013-01-09 73 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並在那裏執行回調/插槽連接。