Search code examples
pyqt5vtkqvtkwidget

PyQt5 + VTK - wglMakeCurrent failed error


Minimum working example:

from sys import exit
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QLabel, QFrame
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import vtkmodules.all as vtk
from vtkmodules.util import numpy_support
import numpy as np

vtk_out = vtk.vtkOutputWindow()
vtk_out.SetDisplayMode(0)

def generate_qtvtk_sphere(parent):
    frame = QFrame(parent)
    vtkWidget = QVTKRenderWindowInteractor(frame)

    ren = vtk.vtkRenderer()
    vtkWidget.GetRenderWindow().AddRenderer(ren)
    iren = vtkWidget.GetRenderWindow().GetInteractor()

    # Create source
    source = vtk.vtkSphereSource()
    source.SetCenter(0, 0, 0)
    source.SetRadius(5.0)

    # Create a mapper
    mapper = vtk.vtkPolyDataMapper()
    mapper.SetInputConnection(source.GetOutputPort())

    # Create an actor
    actor = vtk.vtkActor()
    actor.SetMapper(mapper)

    ren.AddActor(actor)

    ren.ResetCamera()

    iren.Initialize()
    iren.Start()

    return vtkWidget

def generate_qtvtk_imagedata(parent):
    frame = QFrame(parent)
    vtkWidget = QVTKRenderWindowInteractor(frame)

    random_array = np.random.random([10, 600, 800])
    vtk_image_data = vtk.vtkImageData()

    image_array = numpy_support.numpy_to_vtk(random_array.ravel(), deep=True, array_type=vtk.VTK_TYPE_UINT16)
    vtk_image_data.GetPointData().SetScalars(image_array)
    vtk_image_data.Modified()

    reslice = vtk.vtkImageReslice()
    reslice.SetInputData(vtk_image_data)    
    reslice.SetOutputDimensionality(2)
    
    ren = vtk.vtkRenderer()
    vtkWidget.GetRenderWindow().AddRenderer(ren)
    iren = vtkWidget.GetRenderWindow().GetInteractor()

    # Create an actor
    actor = vtk.vtkImageActor()
    actor.GetMapper().SetInputConnection(reslice.GetOutputPort())
    ren.SetBackground(50, 50, 50)

    ren.AddActor(actor)

    ren.ResetCamera()

    interactorStyle = vtk.vtkInteractorStyleImage()
    vtkWidget.SetInteractorStyle(interactorStyle)
    vtkWidget.GetRenderWindow().SetInteractor(vtkWidget)
    vtkWidget.GetRenderWindow().Render()


    iren.Initialize()
    iren.Start()

    return vtkWidget


app = QApplication([])
main_window = QMainWindow()

main_widget = QWidget()
main_layout = QHBoxLayout()
main_widget.setLayout(main_layout)

qtvtk_widget_sphere = generate_qtvtk_sphere(main_widget)
qtvtk_widget_image = generate_qtvtk_imagedata(main_widget)

main_layout.addWidget(qtvtk_widget_image)
main_layout.addWidget(qtvtk_widget_sphere)

main_window.setCentralWidget(main_widget)


main_window.show()
app.exec()

The output of this code should be a pyqt window with a sphere on one side and a randomly-generated black square on the other. The square is representative of the datasets that I normally deal with.

The relevant packages in my conda env are:

  • vtk 9.1.0
  • pyqt5 5.15.7
  • python 3.7.13 (cant upgrade due to dependency on another package)

The full error I get looks like this:

enter image description here


Original post follows:

In my application, I have two QVTKRenderWindowInteractor, on two different QWidgets, that are mostly independent from each other - there's a function outside the interactors that updates the contents of both interactors at the same thing, but that's it.

Whenever the application displays both interactors, I get the following error when the app closes:

2022-08-23 13:51:07.522 (  10.079s) [                ]vtkWin32OpenGLRenderWin:267    ERR| vtkWin32OpenGLRenderWindow (00000194B174E4C0): wglMakeCurrent failed in MakeCurrent(), error: ࣐Ɣ

The error part in the end looks like this on the debugger

enter image description here

and there's usually a lot of these errors that pop up.

My other application (same idea, qt, same interactor, same set-up) has these lines in the beginning of the code

vtk_out = vtkOutputWindow()
vtk_out.SetDisplayMode(0)

which suppresses the errors for that one.

But in my other progra,, I need to use a QWorker/QThread in order to update the interactor, and outputting the error to console doesn't work anymore (it creates a new window with the same error, and then freezes everything).

I just want to know what the heck these errors are and how to get rid of them.

Also, the code I'm using the setup the interactor is as follows:

In the widget:

        self._frame = QGroupBox()
        self.interactor = ViewerPanelVTK(self._frame)

        layout = QVBoxLayout(self)
        layout.addWidget(self.interactor)

where

class ViewerPanelVTK(QVTKRenderWindowInteractor):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.panel_actor = vtkImageActor()
        self.panel_renderer = vtkRenderer()
        self.window = self.GetRenderWindow()

Solution

  • Found the answer myself eventually in the VTK discourse forum.

    Apparently the widget needs to be closed so that this error won't show.

    The sample code from the original answer follows:

    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
    import vtk
    
    class vtkWin(QWidget):
    
        def __init__(self):
            super().__init__()
    
            layout = QVBoxLayout()
            self.setLayout(layout)
            self.vtkWidget = QVTKRenderWindowInteractor()
            layout.addWidget(self.vtkWidget)
            render = vtk.vtkRenderer()
            self.vtkWidget.GetRenderWindow().AddRenderer(render)
    
            cone_a=vtk.vtkConeSource()
            coneMapper = vtk.vtkPolyDataMapper()
            coneMapper.SetInputConnection(cone_a.GetOutputPort())
            coneActor = vtk.vtkActor()
            coneActor.SetMapper(coneMapper)
            render.AddActor(coneActor)
            self.vtkWidget.GetRenderWindow().Render()
    
        def closeEvent(self, QCloseEvent):
            super().closeEvent(QCloseEvent)
            self.vtkWidget.Finalize()     ############################ important
    
    class MainWindow(QWidget):
    
        def __init__(self):
            super().__init__()
    
            layout = QHBoxLayout()
            self.setLayout(layout)
    
            self.w1 = vtkWin()
            self.w2 = vtkWin()
            layout.addWidget(self.w1)
            layout.addWidget(self.w2)
    
        def closeEvent(self, QCloseEvent):
            super().closeEvent(QCloseEvent)
            self.w1.close()
            self.w2.close()
    
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
        w = MainWindow()
        w.show()
        app.exec_()