Fixing parameters reloaded when testing camera. Also fixed app freezing when closing Preferences dialog after using test camera dialog

This commit is contained in:
matlabbe
2026-07-03 01:28:18 -07:00
parent 405be6675a
commit 0b18ede2fb
5 changed files with 69 additions and 11 deletions
+6
View File
@@ -60,6 +60,12 @@ int main(int argc, char* argv[])
QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat()); QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat());
#endif #endif
// Recommended by VTK when using QVTKOpenGLNativeWidget (a QOpenGLWidget): let all VTK
// render widgets share a single OpenGL context, which is needed for correct rendering
// when render widgets live in / move across multiple top-level windows. Must be set
// before QApplication is constructed.
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
/* Create tasks */ /* Create tasks */
QApplication * app = new QApplication(argc, argv); QApplication * app = new QApplication(argc, argv);
app->setStyleSheet("QMessageBox { messagebox-text-interaction-flags: 5; }"); // selectable message box app->setStyleSheet("QMessageBox { messagebox-text-interaction-flags: 5; }"); // selectable message box
+8 -2
View File
@@ -530,15 +530,21 @@ void SensorCaptureThread::mainLoop()
info.odomPose.setNull(); info.odomPose.setNull();
} }
if(!data.imageCompressed().empty() || !data.imageRaw().empty() || !data.laserScanRaw().empty() || (dynamic_cast<DBReader*>(_camera) != 0 && data.id()>0)) // intermediate nodes could not have image set if(this->isKilled())
{
// A kill was requested (e.g. while we were blocked capturing this frame): don't
// publish anything so we never deliver events to handlers that are being torn down.
}
else if(!data.imageCompressed().empty() || !data.imageRaw().empty() || !data.laserScanRaw().empty() || (dynamic_cast<DBReader*>(_camera) != 0 && data.id()>0)) // intermediate nodes could not have image set
{ {
postUpdate(&data, &info); postUpdate(&data, &info);
info.cameraName = _lidar?_lidar->getSerial():_camera->getSerial(); info.cameraName = _lidar?_lidar->getSerial():_camera->getSerial();
info.timeTotal = totalTime.ticks(); info.timeTotal = totalTime.ticks();
this->post(new SensorEvent(data, info)); this->post(new SensorEvent(data, info));
} }
else if(!this->isKilled()) else
{ {
// Not killed but no data: end of stream. Signal consumers once, then stop.
UWARN("no more data..."); UWARN("no more data...");
this->kill(); this->kill();
this->post(new SensorEvent()); this->post(new SensorEvent());
+10
View File
@@ -265,6 +265,16 @@ CloudViewer::~CloudViewer()
{ {
UDEBUG(""); UDEBUG("");
this->clear(); this->clear();
#if VTK_MAJOR_VERSION > 8
// Explicitly release the OpenGL context/resources bound to this widget's native window
// before the render window is torn down.
if(this->renderWindow())
{
this->makeCurrent();
this->renderWindow()->Finalize();
this->doneCurrent();
}
#endif
delete _visualizer; delete _visualizer;
UDEBUG(""); UDEBUG("");
} }
+39 -9
View File
@@ -7793,12 +7793,13 @@ void PreferencesDialog::testOdometry()
_ui->odom_dataBufferSize->value()); _ui->odom_dataBufferSize->value());
odomThread.registerToEventsManager(); odomThread.registerToEventsManager();
// parent = 0 (not 'this'): see testCamera() - avoids the nested-modality crash.
OdometryViewer * odomViewer = new OdometryViewer(10, OdometryViewer * odomViewer = new OdometryViewer(10,
_ui->spinBox_decimation_odom->value(), _ui->spinBox_decimation_odom->value(),
0.0f, 0.0f,
_ui->doubleSpinBox_maxDepth_odom->value(), _ui->doubleSpinBox_maxDepth_odom->value(),
this->getOdomQualityWarnThr(), this->getOdomQualityWarnThr(),
this, 0,
this->getAllParameters()); this->getAllParameters());
odomViewer->setWindowTitle(tr("Odometry viewer")); odomViewer->setWindowTitle(tr("Odometry viewer"));
odomViewer->resize(1280, 480+QPushButton().minimumHeight()); odomViewer->resize(1280, 480+QPushButton().minimumHeight());
@@ -7860,20 +7861,41 @@ void PreferencesDialog::testOdometry()
} }
odomViewer->exec(); odomViewer->exec();
delete odomViewer;
// Tear down the pipes first so no more events are routed to the threads/viewer being
// destroyed, then stop the threads, then delete the viewer. This avoids delivering
// events to a handler that is being torn down.
UEventsManager::removePipe(&cameraThread, &odomThread, "SensorEvent");
if(imuThread)
{
UEventsManager::removePipe(imuThread, &odomThread, "IMUEvent");
}
UEventsManager::removePipe(&odomThread, odomViewer, "OdometryEvent");
UEventsManager::removePipe(odomViewer, &odomThread, "OdometryResetEvent");
if(imuThread) if(imuThread)
{ {
imuThread->join(true); imuThread->join(true);
delete imuThread;
} }
cameraThread.join(true); cameraThread.join(true);
odomThread.join(true); odomThread.join(true);
// deleteLater() (not delete): see testCamera() - avoids a dangling OpenGL platform
// window that crashes in QWindowsWindow::alertWindow when Preferences later closes.
odomViewer->deleteLater();
if(imuThread)
{
delete imuThread;
}
} }
void PreferencesDialog::testCamera() void PreferencesDialog::testCamera()
{ {
CameraViewer * window = new CameraViewer(this, this->getAllParameters()); // Not parented to 'this': the Preferences dialog is itself application-modal, and making
// the viewer a modal *child* of it (nested modality) with an OpenGL/VTK native window
// crashes Qt (QWindowsWindow::alertWindow, this==nullptr) when Preferences later closes.
// exec() below still makes the viewer application-modal, so interaction stays blocked.
CameraViewer * window = new CameraViewer(nullptr, this->getAllParameters());
window->setWindowTitle(tr("Camera viewer")); window->setWindowTitle(tr("Camera viewer"));
window->resize(1280, 480+QPushButton().minimumHeight()); window->resize(1280, 480+QPushButton().minimumHeight());
window->registerToEventsManager(); window->registerToEventsManager();
@@ -7923,12 +7945,16 @@ void PreferencesDialog::testCamera()
cameraThread.start(); cameraThread.start();
window->exec(); window->exec();
delete window; UEventsManager::removePipe(&cameraThread, window, "SensorEvent");
cameraThread.join(true); cameraThread.join(true);
// deleteLater() (not delete): defer destruction to the event loop so Qt finishes
// tearing down the OpenGL widget's context and window-proc subclass and drains
// pending activation messages first.
window->deleteLater();
} }
else else
{ {
delete window; window->deleteLater();
} }
} }
@@ -8394,7 +8420,8 @@ void PreferencesDialog::calibrateOdomSensorExtrinsics()
void PreferencesDialog::testLidar() void PreferencesDialog::testLidar()
{ {
CameraViewer * window = new CameraViewer(this, this->getAllParameters()); // Not parented to 'this': see testCamera() - avoids the nested-modality crash.
CameraViewer * window = new CameraViewer(nullptr, this->getAllParameters());
window->setWindowTitle(tr("Lidar viewer")); window->setWindowTitle(tr("Lidar viewer"));
window->setWindowFlags(Qt::Window); window->setWindowFlags(Qt::Window);
window->resize(1280, 480+QPushButton().minimumHeight()); window->resize(1280, 480+QPushButton().minimumHeight());
@@ -8420,12 +8447,15 @@ void PreferencesDialog::testLidar()
lidarThread.start(); lidarThread.start();
window->exec(); window->exec();
delete window; UEventsManager::removePipe(&lidarThread, window, "SensorEvent");
lidarThread.join(true); lidarThread.join(true);
// deleteLater() (not delete): see testCamera() - avoids a dangling OpenGL platform
// window that crashes in QWindowsWindow::alertWindow when Preferences later closes.
window->deleteLater();
} }
else else
{ {
delete window; window->deleteLater();
} }
} }
+6
View File
@@ -53,6 +53,12 @@ int main(int argc, char * argv[])
QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat()); QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat());
#endif #endif
// Recommended by VTK when using QVTKOpenGLNativeWidget (a QOpenGLWidget): let all VTK
// render widgets share a single OpenGL context, which is needed for correct rendering
// when render widgets live in / move across multiple top-level windows. Must be set
// before QApplication is constructed.
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
#ifdef RTABMAP_PYTHON #ifdef RTABMAP_PYTHON
rtabmap::PythonInterface pythonInterface; rtabmap::PythonInterface pythonInterface;
#endif #endif