2014-11-15 12 views
8

Sto lavorando a un progetto che utilizza una sottoclasse personalizzata di QOpenGLWidget per visualizzare alcuni rendering. Alla fine del metodo paintGL() chiama il metodo update() del widget per attivare un evento ridisegno se è visibile. Ora voglio aggiungere un ulteriore QVTKWidget al mio Ui e lo faccio utilizzando qualcosa di simile:Utilizzo di QVTKWidget e QOpenGLWidget nella stessa UI?

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); 

Il widget VTK viene aggiunta l'interfaccia utente e funzioni come previsto. Il problema è che non appena utilizzo il metodo layout->addWidget()tutti gli altri oggetti QOpenGLWidget diventano neri e non visualizzano nulla. Anche questo nero non è il colore di sfondo dello VTKRenderer perché gli altri widget sono ancora neri anche se cambio il colore di sfondo del widget VTK. Ho controllato e il paintGL() viene ancora chiamato in un ciclo ma non visualizza nulla. Sono abbastanza sicuro di non aver usato alcun codice OpenGL nella mia sottoclasse di widget, quindi suppongo che abbia qualcosa a che fare con l'inizializzazione interna di QOpenGLWidget e QVTKWidget. Lo stesso accade se ometto tutte le chiamate VTK e aggiungo semplicemente il QVTKWidget appena creato.

La cosa divertente è che se ometto la chiamata layout->addWidget(), VTK apre il rendering in una finestra separata e tutti i widget OpenGL funzionano senza problemi. Ma ovviamente voglio incorporare il renderer nel mio ui.

Qualcuno ha esperienza con questo o conosci le insidie ​​in cui potrei essere intervenuto o ci sono problemi comuni che possono causare questo?

BTW: utilizzo un profilo core OpenGL 3.3 con shader personalizzati per la sottoclasse QOpenGLWidget.

MODIFICA: ho rimosso la richiesta per un profilo di base 3.3 e ora utilizza un profilo di compatibilità 4.4. Immagino che ora stia usando lo stesso profilo del VTKRenderer quindi questo può essere escluso come fonte per l'errore.

+0

Bug ancora presente in VTK 7.1 e Qt 5.7. Per me non è solo nero, si blocca. –

+0

Qualcuno ha segnalato questo bug tracker VTK? –

+0

Scusa, non l'ho fatto.Immagino sarebbe anche sensato contribuire con una completa reimplementazione di QVTKWidget utilizzando i più recenti standard Qt OpenGL ... – w1th0utnam3

risposta

11

Quindi non so cosa abbia causato esattamente il problema ma l'ho risolto. Inizialmente ho scoperto che esiste una seconda classe di widget per VTK chiamata QVTKWidget2 ma sfortunatamente non è completamente compatibile con Qt 5.4 perché utilizza le vecchie classi QGL (come QGLWidget anziché QOpenGLWidget). Così ho iniziato a ri-implementarlo come sottoclasse di QOpenGLWidget che era abbastanza semplice. Di seguito sono riportati i file sorgente per la mia classe QVTKWidget3 che funziona con Qt 5.4 per chiunque sia interessato. Ho fatto solo test limitati (perché sto ancora imparando VTK) ma semplici esempi come la visualizzazione di una sfera funzionano.

Ancora: funziona solo con Qt 5.4 (beta) perché le versioni precedenti non forniscono la classe QOpenGLWidget!

file di intestazione: 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 

File di origine: 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

Sto riscontrando lo stesso problema con vtk-6.2 e qt-5.2.1. Con alcuni piccoli adattamenti (per usare 'QGLWidget') la tua soluzione ha funzionato per me. Grazie! – taketwo

+2

Per la cronaca: il Bug esiste ancora con QT5.5 e VTK7 ... E la tua soluzione funziona ancora. Buon lavoro! – GPMueller

Problemi correlati