2014-11-15 6 views
8

Ich arbeite an einem Projekt, das eine benutzerdefinierte Unterklasse von QOpenGLWidget verwendet, um einige Renderings anzuzeigen. Am Ende der paintGL() Methode ruft es die Methode update() des Widgets auf, um ein Repaint-Ereignis auszulösen, wenn es sichtbar ist. Jetzt möchte ich eine zusätzliche QVTKWidget meiner Ui hinzuzufügen und ich so etwas wie dies mit:Verwenden von QVTKWidget und QOpenGLWidget auf derselben Benutzeroberfläche?

QVBoxLayout* layout = findChild<QVBoxLayout*>("layout_simulation"); 
QVTKWidget* widget = new QVTKWidget(); 

// Setup arrow 
vtkSmartPointer<vtkArrowSource> arrowSource = vtkSmartPointer<vtkArrowSource>::New(); 

[more VTK stuff...] 

widget->GetRenderWindow()->AddRenderer(renderer); 
renderer->AddActor(arrowActor); 
renderer->ResetCamera(); 

// Add widget to ui 
layout->addWidget(widget); 

Die VTK-Widget zum ui hinzugefügt wird und wie vorgesehen funktioniert. Das Problem ist, dass sobald ich die layout->addWidget() Methode verwende alle meine anderen QOpenGLWidget Objekte schwarz drehen und nichts anzeigen. Auch dieses Schwarz ist nicht die Hintergrundfarbe des VTKRenderer, weil die anderen Widgets immer noch schwarz sind, auch wenn ich die Hintergrundfarbe des VTK-Widgets ändere. Ich habe überprüft und die paintGL() wird immer noch in einer Schleife aufgerufen, aber es zeigt nichts an. Ich bin ziemlich sicher, dass ich keinen schlechten OpenGL-Code in meiner Widget-Unterklasse verwendet habe, also nehme ich an, dass es etwas mit der internen Initialisierung von QOpenGLWidget und QVTKWidget zu tun hat. Das Gleiche passiert, wenn ich alle VTK-Aufrufe weglasse und einfach das neu erstellte QVTKWidget hinzufüge.

Die lustige Sache ist, dass, wenn ich den layout->addWidget() Aufruf weglasse, öffnet VTK den Renderer in einem separaten Fenster und alle OpenGL-Widgets funktionieren ohne ein Problem. Aber natürlich möchte ich den Renderer in mein UI einbetten.

Hat jemand Erfahrung damit oder kennen Sie Fallstricke, in die ich vielleicht geraten bin oder gibt es irgendwelche allgemeinen Probleme, die das verursachen können?

BTW: Ich verwende ein OpenGL 3.3 Core-Profil mit benutzerdefinierten Shadern für meine QOpenGLWidget Unterklasse.

EDIT: Ich habe meine Anfrage für ein 3.3-Core-Profil entfernt und jetzt verwendet es ein 4.4 Kompatibilitätsprofil. Ich nehme an, dass es jetzt das gleiche Profil wie das VTKRenderer verwendet, so dass dies als eine Quelle für den Fehler ausgeschlossen werden kann.

+0

Bug noch in VTK 7.1 und Qt 5.7. Für mich ist es nicht nur schwarz, es stürzt ab. –

+0

Hat jemand diesen VTK Bug Tracker gemeldet? –

+0

Tut mir leid, habe ich nicht.Ich denke, es wäre auch sinnvoll, eine vollständige Neuimplementierung von QVTKWidget mit den neuesten Qt OpenGL-Standards beizutragen ... – w1th0utnam3

Antwort

11

Also ich weiß nicht, was genau das Problem verursacht, aber ich habe es gelöst. Zuerst habe ich herausgefunden, dass es eine zweite Widget-Klasse für VTK gibt, genannt QVTKWidget2, aber leider ist sie nicht vollständig kompatibel zu Qt 5.4, weil sie die alten QGL-Klassen verwendet (wie QGLWidget anstelle von QOpenGLWidget). Also fing ich an, es als eine Unterklasse von QOpenGLWidget umzusetzen, was ziemlich einfach war. Im Folgenden sind die Quelldateien für meine Klasse QVTKWidget3, die mit Qt 5.4 für jeden, der daran interessiert ist, funktioniert. Ich habe nur begrenzte Tests gemacht (weil ich immer noch VTK lerne), aber einfache Beispiele wie das Anzeigen einer Kugel funktionieren.

Nochmals: Dies funktioniert nur mit Qt 5.4 (beta), da ältere Versionen nicht die QOpenGLWidget-Klasse bieten!

Headerdatei: qvtkwidget3.h

#ifndef QVTKWIDGET3_H 
#define QVTKWIDGET3_H 

#include "vtkSmartPointer.h" 
#include "vtkGenericOpenGLRenderWindow.h" 
#include "vtkEventQtSlotConnect.h" 

#include "QVTKInteractorAdapter.h" 
#include "QVTKInteractor.h" 

#include <QOpenGLWidget> 
#include <QSurfaceFormat> 

class QVTKWidget3 : public QOpenGLWidget 
{ 
    Q_OBJECT 

public: 
    QVTKWidget3(QWidget *parent = NULL, Qt::WindowFlags f = 0, QSurfaceFormat format = QSurfaceFormat::defaultFormat()); 
    virtual ~QVTKWidget3(); 

    //! Set a custom render window 
    virtual void SetRenderWindow(vtkGenericOpenGLRenderWindow*); 
    //! Returns the curren render window (creates one if none exists) 
    virtual vtkGenericOpenGLRenderWindow* GetRenderWindow(); 

    //! Returns interactor of the current render window 
    virtual QVTKInteractor* GetInteractor(); 

public slots: 
    //! Slot to make this vtk render window current 
    virtual void MakeCurrent(); 
    //! Slot called when vtk wants to know if the context is current 
    virtual void IsCurrent(vtkObject* caller, unsigned long vtk_event, void* client_data, void* call_data); 
    //! Slot called when vtk wants to frame the window 
    virtual void Frame(); 
    //! Slot called when vtk wants to start the render 
    virtual void Start(); 
    //! Slot called when vtk wants to end the render 
    virtual void End(); 
    //! Slot called when vtk wants to know if a window is direct 
    virtual void IsDirect(vtkObject* caller, unsigned long vtk_event, void* client_data, void* call_data); 
    //! Slot called when vtk wants to know if a window supports OpenGL 
    virtual void SupportsOpenGL(vtkObject* caller, unsigned long vtk_event, void* client_data, void* call_data); 

protected: 
    //! Initialize handler 
    virtual void initializeGL(); 
    //! Paint handler 
    virtual void paintGL(); 
    //! Resize handler 
    virtual void resizeGL(int, int); 
    //! Move handler 
    virtual void moveEvent(QMoveEvent* event); 

    virtual void mousePressEvent(QMouseEvent* event); 
    virtual void mouseMoveEvent(QMouseEvent* event); 
    virtual void mouseReleaseEvent(QMouseEvent* event); 
    virtual void keyPressEvent(QKeyEvent* event); 
    virtual void keyReleaseEvent(QKeyEvent* event); 
    virtual void enterEvent(QEvent*); 
    virtual void leaveEvent(QEvent*); 
    virtual void wheelEvent(QWheelEvent*); 

    virtual void contextMenuEvent(QContextMenuEvent*); 
    virtual void dragEnterEvent(QDragEnterEvent*); 
    virtual void dragMoveEvent(QDragMoveEvent*); 
    virtual void dragLeaveEvent(QDragLeaveEvent*); 
    virtual void dropEvent(QDropEvent*); 

    virtual bool focusNextPrevChild(bool); 

    // Members 
    vtkGenericOpenGLRenderWindow* m_renWin; 
    QVTKInteractorAdapter* m_irenAdapter; 
    vtkSmartPointer<vtkEventQtSlotConnect> m_connect; 

private: 
    //! unimplemented operator= 
    QVTKWidget3 const& operator=(QVTKWidget3 const&); 
    //! unimplemented copy 
    QVTKWidget3(const QVTKWidget3&); 
}; 

#endif // QVTKWIDGET3_H 

Quelldatei: qvtkwidget3.cpp

#include "qvtkwidget3.h" 

#include "vtkRenderWindowInteractor.h" 
#include "vtkInteractorStyle.h" 
#include "vtkInteractorStyleTrackballCamera.h" 

#include <QResizeEvent> 

QVTKWidget3::QVTKWidget3(QWidget *parent, Qt::WindowFlags f, QSurfaceFormat format) 
    : QOpenGLWidget(parent, f) 
    , m_renWin(nullptr) 
{ 
    // VTK requires a compatibility profile 
    format.setProfile(QSurfaceFormat::CompatibilityProfile); 
    setFormat(format); 

    // Initialize interactors 
    m_irenAdapter = new QVTKInteractorAdapter(this); 
    m_connect = vtkSmartPointer<vtkEventQtSlotConnect>::New(); 
} 

// Destructor 
QVTKWidget3::~QVTKWidget3() 
{ 
    // Following line is not needed. 
    // get rid of the VTK window 
    // this->SetRenderWindow(NULL); 
} 

// GetRenderWindow 
vtkGenericOpenGLRenderWindow* QVTKWidget3::GetRenderWindow() 
{ 
    if (this->m_renWin == nullptr) 
    { 
     // create a default vtk window 
     vtkGenericOpenGLRenderWindow* win = vtkGenericOpenGLRenderWindow::New(); 
     this->SetRenderWindow(win); 
    } 

    return this->m_renWin; 
} 

// SetRenderWindow 
void QVTKWidget3::SetRenderWindow(vtkGenericOpenGLRenderWindow* w) 
{ 
    // do nothing if we don't have to 
    if(w == this->m_renWin) { 
     return; 
    } 

    // unregister previous window 
    if(this->m_renWin != nullptr) { 
     this->m_renWin->Finalize(); 
     this->m_renWin->SetMapped(0); 

     m_connect->Disconnect(m_renWin, vtkCommand::WindowMakeCurrentEvent, this, SLOT(MakeCurrent())); 
     m_connect->Disconnect(m_renWin, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*))); 
     m_connect->Disconnect(m_renWin, vtkCommand::WindowFrameEvent, this, SLOT(Frame())); 
     m_connect->Disconnect(m_renWin, vtkCommand::StartEvent, this, SLOT(Start())); 
     m_connect->Disconnect(m_renWin, vtkCommand::EndEvent, this, SLOT(End())); 
     m_connect->Disconnect(m_renWin, vtkCommand::WindowIsDirectEvent, this, SLOT(IsDirect(vtkObject*, unsigned long, void*, void*))); 
     m_connect->Disconnect(m_renWin, vtkCommand::WindowSupportsOpenGLEvent, this, SLOT(SupportsOpenGL(vtkObject*, unsigned long, void*, void*))); 
    } 

    // now set the window 
    this->m_renWin = w; 

    if(this->m_renWin != nullptr) { 
     // if it is mapped somewhere else, unmap it 
     this->m_renWin->Finalize(); 
     this->m_renWin->SetMapped(1); 

     // tell the vtk window what the size of this window is 
     this->m_renWin->SetSize(this->width(), this->height()); 
     this->m_renWin->SetPosition(this->x(), this->y()); 

     // if an interactor wasn't provided, we'll make one by default 
     if(this->m_renWin->GetInteractor() == NULL) 
     { 
      // create a default interactor 
      QVTKInteractor* iren = QVTKInteractor::New(); 
      iren->SetUseTDx(false); 
      this->m_renWin->SetInteractor(iren); 
      iren->Initialize(); 

      // now set the default style 
      vtkInteractorStyle* s = vtkInteractorStyleTrackballCamera::New(); 
      iren->SetInteractorStyle(s); 

      iren->Delete(); 
      s->Delete(); 
     } 

     // tell the interactor the size of this window 
     this->m_renWin->GetInteractor()->SetSize(this->width(), this->height()); 

     m_connect->Connect(m_renWin, vtkCommand::WindowMakeCurrentEvent, this, SLOT(MakeCurrent())); 
     m_connect->Connect(m_renWin, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*))); 
     m_connect->Connect(m_renWin, vtkCommand::WindowFrameEvent, this, SLOT(Frame())); 
     m_connect->Connect(m_renWin, vtkCommand::StartEvent, this, SLOT(Start())); 
     m_connect->Connect(m_renWin, vtkCommand::EndEvent, this, SLOT(End())); 
     m_connect->Connect(m_renWin, vtkCommand::WindowIsDirectEvent, this, SLOT(IsDirect(vtkObject*, unsigned long, void*, void*))); 
     m_connect->Connect(m_renWin, vtkCommand::WindowSupportsOpenGLEvent, this, SLOT(SupportsOpenGL(vtkObject*, unsigned long, void*, void*))); 
    } 
} 

// GetInteractor 
QVTKInteractor* QVTKWidget3::GetInteractor() 
{ 
    return QVTKInteractor::SafeDownCast(this->GetRenderWindow()->GetInteractor()); 
} 

// Initialize 
void QVTKWidget3::initializeGL() 
{ 
    if(this->m_renWin == nullptr) { 
     return; 
    } 

    this->m_renWin->OpenGLInitContext(); 
} 

// Paint 
void QVTKWidget3::paintGL() 
{ 
    vtkRenderWindowInteractor* iren = nullptr; 
    if(this->m_renWin != nullptr) { 
     iren = this->m_renWin->GetInteractor(); 
    } 

    if(iren == nullptr || !iren->GetEnabled()) { 
     return; 
    } 

    iren->Render(); 
} 

// Resize 
void QVTKWidget3::resizeGL(int w, int h) 
{ 
    if(this->m_renWin == nullptr) { 
     return; 
    } 

    this->m_renWin->SetSize(w,h); 

    // and update the interactor 
    if(this->m_renWin->GetInteractor() != NULL) { 
     QResizeEvent e(QSize(w,h), QSize()); 
     m_irenAdapter->ProcessEvent(&e, this->m_renWin->GetInteractor()); 
    } 
} 

// Move 
void QVTKWidget3::moveEvent(QMoveEvent* e) 
{ 
    QWidget::moveEvent(e); 

    if(this->m_renWin == nullptr) { 
     return; 
    } 

    this->m_renWin->SetPosition(this->x(), this->y()); 
} 


// -------- 
// Slots 
// -------- 

void QVTKWidget3::Start() 
{ 
    makeCurrent(); 
    m_renWin->PushState(); 
    m_renWin->OpenGLInitState(); 
} 

void QVTKWidget3::End() 
{ 
    m_renWin->PopState(); 
} 

void QVTKWidget3::MakeCurrent() 
{ 
    return; 
    // Automaticly handled by QOpenGLWidget 
    // this->makeCurrent(); 
} 

void QVTKWidget3::IsCurrent(vtkObject*, unsigned long, void*, void* call_data) 
{ 
    bool* ptr = reinterpret_cast<bool*>(call_data); 
    *ptr = (int)true; 
} 

void QVTKWidget3::IsDirect(vtkObject*, unsigned long, void*, void* call_data) 
{ 
    int* ptr = reinterpret_cast<int*>(call_data); 
    *ptr = (int)true; 
} 

void QVTKWidget3::SupportsOpenGL(vtkObject*, unsigned long, void*, void* call_data) 
{ 
    int* ptr = reinterpret_cast<int*>(call_data); 
    *ptr = (int)true; 
} 

void QVTKWidget3::Frame() 
{ 
    if(m_renWin->GetSwapBuffers()) { 
     this->update(); 
    } 

    // This callback will call swapBuffers() for us 
    // because sometimes VTK does a render without coming through this paintGL() 

    // FOLLOWING NOT TESTED FOR QOPENGLWIDGET 
    // if you want paintGL to always be called for each time VTK renders 
    // 1. turn off EnableRender on the interactor, 
    // 2. turn off SwapBuffers on the render window, 
    // 3. add an observer for the RenderEvent coming from the interactor 
    // 4. implement the callback on the observer to call updateGL() on this widget 
    // 5. overload QVTKWidget3::paintGL() to call m_renWin->Render() instead iren->Render() 
} 

// ---------------------- 
// Interaction handlers 
// ---------------------- 

/*! handle mouse press event 
*/ 
void QVTKWidget3::mousePressEvent(QMouseEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 

} 

/*! handle mouse move event 
*/ 
void QVTKWidget3::mouseMoveEvent(QMouseEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

/*! handle enter event 
*/ 
void QVTKWidget3::enterEvent(QEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

/*! handle leave event 
*/ 
void QVTKWidget3::leaveEvent(QEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

/*! handle mouse release event 
*/ 
void QVTKWidget3::mouseReleaseEvent(QMouseEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

/*! handle key press event 
*/ 
void QVTKWidget3::keyPressEvent(QKeyEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

/*! handle key release event 
*/ 
void QVTKWidget3::keyReleaseEvent(QKeyEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

void QVTKWidget3::wheelEvent(QWheelEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

void QVTKWidget3::contextMenuEvent(QContextMenuEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

void QVTKWidget3::dragEnterEvent(QDragEnterEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

void QVTKWidget3::dragMoveEvent(QDragMoveEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

void QVTKWidget3::dragLeaveEvent(QDragLeaveEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

void QVTKWidget3::dropEvent(QDropEvent* e) 
{ 
    if(this->m_renWin) 
    { 
     m_irenAdapter->ProcessEvent(e, this->m_renWin->GetInteractor()); 
    } 
} 

bool QVTKWidget3::focusNextPrevChild(bool) 
{ 
    return false; 
} 
+2

Ich habe das gleiche Problem mit vtk-6.2 und qt-5.2.1. Mit ein paar kleinen Anpassungen (um 'QGLWidget' zu verwenden) hat Ihre Lösung für mich funktioniert. Vielen Dank! – taketwo

+2

Für den Rekord: der Bug existiert immer noch mit QT5.5 und VTK7 ... Und Ihre Lösung funktioniert immer noch. Gut gemacht! – GPMueller