我正在尝试将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
用于管理回调。但是,如果我向其添加回调观察器,则不如直接将它们添加到渲染窗口那样准确。
答案 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
并执行回调/插槽连接。