Qt嵌入OSG渲染中osgGA::StateSetManipulator的T/L按键无响应排查
Qt嵌入OSG后StateSetManipulator部分按键无响应问题排查
在Qt中嵌入OSG渲染场景,将osgQOpenGLWidget放入作为QMainWindow子类中心部件的QTabWidget多页控件内,添加osgGA::StateSetManipulator用于状态操作。目前W(线框模式切换)、B(背面剔除切换)按键功能正常,但T(纹理显示切换)、L(光照显示切换)按键无响应,以下为问题代码及排查方案:
问题代码实现
头文件(hpp)
class V3dViewerWidget : public QMainWindow { Q_OBJECT public: V3dViewerWidget(QWidget* parent = nullptr); V3dViewerWidget(osg::ArgumentParser& arguments, QWidget* parent = nullptr); V3dViewerWidget(QString externalfile, QWidget* parent = nullptr); protected slots: void initData(); private: void WidgetUIinit(); void setCentralData(); void setCentralData(osg::ArgumentParser& argument); private: QTabWidget* _mTabCenteralWidget = nullptr; };
实现文件(cpp)
V3dViewerWidget::V3dViewerWidget(QWidget* parent) : QMainWindow(parent) { WidgetUIinit(); setCentralData(); } V3dViewerWidget::V3dViewerWidget(osg::ArgumentParser& arguments, QWidget* parent) : QMainWindow(parent) { WidgetUIinit(); setCentralData(arguments); } V3dViewerWidget::V3dViewerWidget(QString externalfile, QWidget* parent) : QMainWindow(parent) { WidgetUIinit(); setCentralData(); } void V3dViewerWidget::WidgetUIinit() { #ifdef HIDE_COMPANY_INFO setWindowTitle(tr("Drone_image_modeling_tool") + tr(" Viewer")); //%1 Viewer #else setWindowTitle(QString("%1 Viewer").arg(PRODUCT_NAME)); setWindowIcon(QIcon(VIEWER_ICON)); #endif this->setMinimumSize(800, 600); // tab部件 _mTabCenteralWidget = new QTabWidget(this); QPalette backcolor(QPalette::Background, Qt::darkGray); _mTabCenteralWidget->setAutoFillBackground(true); _mTabCenteralWidget->setPalette(backcolor); // 设置中心部件 this->setCentralWidget(_mTabCenteralWidget); } void V3dViewerWidget::initData() { // 未执行 osgQOpenGLWidget* sender = dynamic_cast<osgQOpenGLWidget*>(QObject::sender()); if (!sender) return; } void V3dViewerWidget::setCentralData() { // 创建osgQOpenGLWidget osgQOpenGLWidget widget; // 初始化 widget.setMouseTracking(true); widget.setFocusPolicy(Qt::StrongFocus); // 数据加载 connect(&widget, SIGNAL(initialized()), this, SLOT(initData())); } void V3dViewerWidget::setCentralData(osg::ArgumentParser& argument) { // 创建osgQOpenGLWidget osgQOpenGLWidget* widget = new osgQOpenGLWidget(&argument); // 初始化 widget->setMouseTracking(true); widget->setFocusPolicy(Qt::StrongFocus); // 添加标签页 _mTabCenteralWidget->addTab(widget, "osgb_test"); // 数据加载 connect(widget, &osgQOpenGLWidget::initialized, [&argument, widget]() { // 设置视口操作器与事件 osgViewer::Viewer* viewer = widget->getOsgViewer(); widget->getOsgViewer()->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet())); widget->getOsgViewer()->setCameraManipulator(new osgGA::TrackballManipulator()); // 加载模型 osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("D:/x/View_test/test.osgb"); // osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(argument); if (!loadedModel) { return; } osgUtil::Optimizer optimizer; optimizer.optimize(loadedModel); // 设置场景数据 widget->getOsgViewer()->setSceneData(loadedModel.get()); }); }
主函数(main)
int main(int argc, char** argv) { // OpenGL设置 QSurfaceFormat format = QSurfaceFormat::defaultFormat(); #ifdef OSG_GL3_AVAILABLE format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); format.setRenderableType(QSurfaceFormat::OpenGL); format.setOption(QSurfaceFormat::DebugContext); #else format.setVersion(2, 0); format.setProfile(QSurfaceFormat::CompatibilityProfile); format.setRenderableType(QSurfaceFormat::OpenGL); format.setOption(QSurfaceFormat::DebugContext); #endif format.setDepthBufferSize(24); // format.setAlphaBufferSize(8); format.setSamples(8); format.setStencilBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); QSurfaceFormat::setDefaultFormat(format); // 应用程序 QApplication qapp(argc, argv); // 显示部件 osg::ArgumentParser arguments(&argc, argv); V3dViewerWidget w(arguments); w.show(); return qapp.exec(); }
可正常运行的示例代码
int main(int argc, char** argv) { QSurfaceFormat format = QSurfaceFormat::defaultFormat(); #ifdef OSG_GL3_AVAILABLE format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); format.setRenderableType(QSurfaceFormat::OpenGL); format.setOption(QSurfaceFormat::DebugContext); #else format.setVersion(2, 0); format.setProfile(QSurfaceFormat::CompatibilityProfile); format.setRenderableType(QSurfaceFormat::OpenGL); format.setOption(QSurfaceFormat::DebugContext); #endif format.setDepthBufferSize(24); // format.setAlphaBufferSize(8); format.setSamples(8); format.setStencilBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); QSurfaceFormat::setDefaultFormat(format); QApplication qapp(argc, argv); // QTabWidget Twidget; osgQOpenGLWidget mwidget; osgQOpenGLWidget ms_widget; mwidget.setFocusPolicy(Qt::StrongFocus); ms_widget.setFocusPolicy(Qt::StrongFocus); Twidget.addTab(&mwidget, "osgb_test"); Twidget.addTab(&ms_widget, "ply_test"); QObject::connect(&mwidget, &osgQOpenGLWidget::initialized, [&]() { osgViewer::Viewer* viewer = mwidget.getOsgViewer(); if (!viewer) { qWarning("Failed to get OSG Viewer"); return -1; } viewer->setCameraManipulator(new osgGA::TrackballManipulator()); viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet())); osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("D:/x/View_test/test.osgb"); osgUtil::Optimizer optimizer; optimizer.optimize(loadedModel); viewer->setSceneData(loadedModel); return 0; }); QObject::connect(&ms_widget, &osgQOpenGLWidget::initialized, [&]() { osgViewer::Viewer* viewer = ms_widget.getOsgViewer(); if (!viewer) { qWarning("Failed to get OSG Viewer"); return -1; } viewer->setCameraManipulator(new osgGA::TrackballManipulator()); osgGA::StateSetManipulator* state = new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()); viewer->addEventHandler(state); osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("E:/x/mesh.ply"); osgUtil::Optimizer optimizer; optimizer.optimize(loadedModel); viewer->setSceneData(loadedModel); return 0; }); Twidget.show(); return qapp.exec(); }
问题原因与解决办法
核心原因
- QTabWidget拦截按键:Qt的
QTabWidget默认会拦截部分按键(如T、L)作为潜在的标签页快捷键,导致这些按键无法传递到下层的osgQOpenGLWidget。 - 焦点未正确设置:即使给
osgQOpenGLWidget设置了Qt::StrongFocus,控件也可能未实际获得焦点,按键事件被上层窗口部件捕获。
解决步骤
1. 自定义QTabWidget放行指定按键
重写QTabWidget的事件过滤逻辑,阻止其拦截T、L按键:
class CustomTabWidget : public QTabWidget { protected: bool eventFilter(QObject* obj, QEvent* event) override { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); // 放行T、L按键,让OSG处理 if (keyEvent->key() == Qt::Key_T || keyEvent->key() == Qt::Key_L) { return false; } } return QTabWidget::eventFilter(obj, event); } };
将原代码中的QTabWidget* _mTabCenteralWidget替换为CustomTabWidget* _mTabCenteralWidget,初始化时创建CustomTabWidget实例。
2. 确保osgQOpenGLWidget获得焦点
在osgQOpenGLWidget的initialized回调中添加焦点设置:
connect(widget, &osgQOpenGLWidget::initialized, [&argument, widget]() { osgViewer::Viewer* viewer = widget->getOsgViewer(); widget->getOsgViewer()->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet())); widget->getOsgViewer()->setCameraManipulator(new osgGA::TrackballManipulator()); // 强制设置控件获得焦点 widget->setFocus(); // 后续模型加载代码... });
3. 验证事件传递(可选)
自定义osgQOpenGLWidget重写按键事件,确认按键是否到达控件:
class CustomOSGWidget : public osgQOpenGLWidget { protected: void keyPressEvent(QKeyEvent* event) override { qDebug() << "收到按键:" << event->key(); osgQOpenGLWidget::keyPressEvent(event); } };
替换原代码中的osgQOpenGLWidget为该自定义类,运行后查看控制台输出,确认T、L按键是否被捕获。
内容的提问来源于stack exchange,提问作者ZH Huang
相关产品推荐
相关产品推荐

