Текст исчезает в QOpenGLWidget после расстыковки

#qt5 #openscenegraph #qdockwidget #qopenglwidget

#qt5 #openscenegraph #qdockwidget #qopenglwidget

Вопрос:

Я пытаюсь интегрировать Qt5 и OpenSceneGraph. Я нашел этот минимальный пример встраивания.

Когда я инкапсулирую виджет, определенный в примере, в QDockWidget и добавляю к примеру простую текстовую метку, текст исчезает при отсоединении окна контейнера. Когда я повторно закрываю окно, текст больше не отображается.

Я уже задавал этот вопрос на форуме OpenSceneGraph, но безуспешно. Я предполагаю, что это как-то связано с методами, связанными с GL, и внутренней перепрошивкой виджетов.

В моем примере по сравнению с оригиналом изменены только конструктор и основная функция.

Это мой модифицированный пример (main.cpp ):

 #include<QApplication> 
#include<QMainWindow> 
#include<QOpenGLWidget> 
#include<QMouseEvent> 
#include<QWheelEvent> 
#include<QDesktopWidget> 
#include<QScreen> 
#include<QtGlobal> 
#include<QWindow> 
#include<QWidget> 
#include<QDockWidget> 
#include<QVBoxLayout> 

#include<osg/ref_ptr> 
#include<osgViewer/GraphicsWindow> 
#include<osgText/Text> 
#include<osgViewer/Viewer> 
#include<osg/Camera> 
#include<osg/ShapeDrawable> 
#include<osg/StateSet> 
#include<osg/Material> 
#include<osgGA/EventQueue> 
#include<osgGA/TrackballManipulator> 

#include <iostream> 
#include <stdio.h> 

class QtOSGWidget : public QOpenGLWidget 
{

public: 
    QtOSGWidget(qreal scaleX, qreal scaleY, QWidget* parent = 0) 
      : QOpenGLWidget(parent) 
        , _mGraphicsWindow(new osgViewer::GraphicsWindowEmbedded( this->x(), this->y(), 
                                                                 this->width(), this->height() ) ) 
        , _mViewer(new osgViewer::Viewer) 
        , m_scaleX(scaleX) 
        , m_scaleY(scaleY) 
    { 
        osg::Cylinder* cylinder    = new osg::Cylinder( osg::Vec3( 0.f, 0.f, 0.f ), 0.25f, 0.5f ); 
        osg::ShapeDrawable* sd = new osg::ShapeDrawable( cylinder ); 
        sd->setColor( osg::Vec4( 0.8f, 0.5f, 0.2f, 1.f ) ); 
        osg::Geode* geode = new osg::Geode; 
        geode->addDrawable(sd); 

        // adding text to the visualization 
        osgText::Text * test = new osgText::Text(); 
        test->setDataVariance(osg::Object::DYNAMIC); 

        test->setCharacterSize(1.0); 
        test->setColor(osg::Vec4(0.0, 0.0, 0.0, 1.0)); 
        test->setAlignment(osgText::Text::CENTER_BOTTOM); 
        test->setAxisAlignment(osgText::TextBase::SCREEN); 
        test->setCharacterSizeMode(osgText::Text::OBJECT_COORDS); 
        test->setText("CYLINDER"); 
        geode->addDrawable(test); 
        // end adding text 

        osg::Camera* camera = new osg::Camera; 
        camera->setViewport( 0, 0, this->width(), this->height() ); 
        camera->setClearColor( osg::Vec4( 0.9f, 0.9f, 1.f, 1.f ) ); 
        float aspectRatio = static_cast<float>( this->width()) / static_cast<float>( this->height() ); 
        camera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f ); 
        camera->setGraphicsContext( _mGraphicsWindow ); 

        _mViewer->setCamera(camera); 
        _mViewer->setSceneData(geode); 
        osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator; 
        manipulator->setAllowThrow( false ); 
        this->setMouseTracking(true); 
        _mViewer->setCameraManipulator(manipulator); 
        _mViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded); 
       // _mViewer->realize(); 
    } 


    virtual ~QtOSGWidget(){} 

    void setScale(qreal X, qreal Y) 
    { 
        m_scaleX = X; 
        m_scaleY = Y; 
        this->resizeGL(this->width(), this->height()); 
    } 

protected: 

    virtual void paintGL() 
    { 
        _mViewer->frame(); 
    } 

    virtual void resizeGL( int width, int height ) 
    { 
        this->getEventQueue()->windowResize(this->x()*m_scaleX, this->y() * m_scaleY, width*m_scaleX, height*m_scaleY); 
        _mGraphicsWindow->resized(this->x()*m_scaleX, this->y() * m_scaleY, width*m_scaleX, height*m_scaleY); 
        osg::Camera* camera = _mViewer->getCamera(); 
        camera->setViewport(0, 0, this->width()*m_scaleX, this->height()* m_scaleY); 
    } 

    virtual void initializeGL()
    { 
        osg::Geode* geode = dynamic_cast<osg::Geode*>(_mViewer->getSceneData()); 
        osg::StateSet* stateSet = geode->getOrCreateStateSet(); 
        osg::Material* material = new osg::Material; 
        material->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE ); 
        stateSet->setAttributeAndModes( material, osg::StateAttribute::ON ); 
        stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON ); 
    } 

    virtual void mouseMoveEvent(QMouseEvent* event) 
    { 
      this->getEventQueue()->mouseMotion(event->x()*m_scaleX, event->y()*m_scaleY); 
    } 

    virtual void mousePressEvent(QMouseEvent* event) 
    { 
        unsigned int button = 0; 
        switch (event->button())
        { 
            case Qt::LeftButton: 
                button = 1; 
                break; 
            case Qt::MiddleButton: 
                button = 2; 
                break; 
            case Qt::RightButton: 
                button = 3; 
                break; 
            default: 
                break; 
        } 
        this->getEventQueue()->mouseButtonPress(event->x()*m_scaleX, event->y()*m_scaleY, button); 
    } 

    virtual void mouseReleaseEvent(QMouseEvent* event) 
    { 
        unsigned int button = 0; 
        switch (event->button())
        { 
            case Qt::LeftButton: 
                button = 1; 
                break; 
            case Qt::MiddleButton: 
                button = 2; 
                break; 
            case Qt::RightButton: 
                button = 3; 
                break; 
            default: 
                break; 
        } 
        this->getEventQueue()->mouseButtonRelease(event->x()*m_scaleX, event->y()*m_scaleY, button); 
    } 

    virtual void wheelEvent(QWheelEvent* event) 
    { 
        int delta = event->delta(); 
        osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ? 
                  osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN; 
        this->getEventQueue()->mouseScroll(motion); 
    } 

    virtual bool event(QEvent* event) 
    { 
        bool handled = QOpenGLWidget::event(event); 
        this->update(); 
        return handled; 
    } 

private: 

    osgGA::EventQueue* getEventQueue() const 
    { 
        osgGA::EventQueue* eventQueue = _mGraphicsWindow->getEventQueue(); 
        return eventQueue; 
    } 

    osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> _mGraphicsWindow; 
    osg::ref_ptr<osgViewer::Viewer> _mViewer; 
    qreal m_scaleX, m_scaleY; 
}; 

int main(int argc, char** argv) 
{ 
    // This was necessary for keeping the context when undocking
    // without it nothing is shown on the widget when gets undocked 
    QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); 

    QApplication qapp(argc, argv); 

    QMainWindow window; 

    // Here starts code to put the QtOSGWidget inside a dock area 
    QDockWidget * visDock = new QDockWidget(amp;window); 
    visDock->setFloating(false); 
    visDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); 
    visDock->setAllowedAreas(Qt::TopDockWidgetArea); 

    QWidget * dockWidgetContent = new QWidget(); 

    QVBoxLayout * verticalLayout = new QVBoxLayout(dockWidgetContent); 
    verticalLayout->setSpacing(6); 
    verticalLayout->setContentsMargins(11, 11, 11, 11); 

    QWidget * containerWidget = new QWidget(dockWidgetContent); 
    QHBoxLayout * horizontalLayout = new QHBoxLayout(containerWidget); 
    horizontalLayout->setSpacing(0); 
    horizontalLayout->setContentsMargins(11, 11, 11, 11); 
    horizontalLayout->setContentsMargins(0, 0, 0, 0); 

    QtOSGWidget* widget = new QtOSGWidget(1, 1, containerWidget); 

    horizontalLayout->addWidget(widget); 

    verticalLayout->addWidget(containerWidget); 

    visDock->setWidget(dockWidgetContent); 

    window.addDockWidget(static_cast<Qt::DockWidgetArea>(4), visDock); 

    // No central widget is used for the example 
    window.setCentralWidget(Q_NULLPTR); 
    window.show(); 

    return qapp.exec(); 
}
  

Ответ №1:

После _mViewer->setSceneData(geode); добавления этого:

 _mGraphicsWindow->init();
initializeGL();
  

и измените метод

 virtual void paintGL() { 
    _mViewer->frame(); 
}
  

Для

 virtual void paintGL() {
    _mGraphicsWindow->decrementContextIDUsageCount(_mGraphicsWindow->getMaxContextID());
    _mGraphicsWindow->releaseContext();
    _mGraphicsWindow->init(); 
    _mViewer->frame(); 
}
  

И добавьте утончения к основной функции:

 QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
  

решит вашу проблему.