<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2016-06-27 9:09 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">2016-06-26 13:31 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>2016-06-26 13:06 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br></span><span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div><div><div><div><div>Hi,<br><br>In my quest to create a PyQt5 widget based on QOpenGLWidget for showing/interacting with VTK, I now have something that seems to work (including the whole thing as a runnable example below).<br></div></div></div></div></div></div></div></div></div></div></div></blockquote><div><br></div></span><div>It was a little too early to say "seems to work": When trying to show one of the volumes I need to render, I get<br><br>(gui) [estan@pyret orexplore.gui]$ python -m orexplore.gui.main<br>enabling depth test<br>ERROR: In /home/estan/Blandat/vtk-python3/src/VTK-7.0.0/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx, line 1682<br>vtkGenericOpenGLRenderWindow (0x308c3f0): Hardware does not support the number of textures defined.<br></div></div></div></div></blockquote></span></div></div></div></blockquote><div><br></div><div>Searching around for this error, the only thing I could find was this old thread from sept 2014 on the vtk-developers list:<br><br>    <a href="http://public.kitware.com/pipermail/vtk-developers/2014-September/015357.html">http://public.kitware.com/pipermail/vtk-developers/2014-September/015357.html</a><br><br></div><div>The poster speaks of some tests that were failing with that error back then. Ken replied that he thought there might be some leak in one of the texture resources in the OpenGL2 backend.<br><br>@Ben: Could that still be the case, and the reason for my error?<br><br></div><div>Elvis<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br>Segmentation fault (core dumped)<br>(gui) [estan@pyret orexplore.gui]$<br><br></div><div>on my Sandybridge laptop :/<br><br></div><div>Anyone know if I'd be able to use the old OpenGL backend here?<span><font color="#888888"><br></font></span></div></div></div></div></blockquote><div><br></div></span><div>I can now confirm that I'm getting the same error on my Haswell work laptop (which is using the OpenGL2 backend) :( Anyone know if there's a way to solve this or what I should look into?<br><br>The volume I'm trying to render is not particularly big (2000x120x120, float), and it renders fine if I use a QGLWidget to back my VTK widget instead of QOpenGLWidget. So I'm suspecting it might have something to do with how I set up my QOpenGLWidget.<br><br></div><div>What I'm doing to configure it is simply:<span class=""><br><br>        # Request OpenGL 3.2 compatibility profile and enable multi-sampling<br></span>        surfaceFormat = QSurfaceFormat.defaultFormat()<span class=""><br>        surfaceFormat.setMajorVersion(3)<br>        surfaceFormat.setMinorVersion(2)<br>        surfaceFormat.setProfile(QSurfaceFormat.CompatibilityProfile)<br>        surfaceFormat.setSamples(8)<br>        self.setFormat(surfaceFormat)<br></span></div><div><br></div><div>The whole reason I'm trying to get QOpenGLWidget working is that QGLWidget does not have a setFormat in PyQt5, since it doesn't wrap functions marked "obsolete" in Qt, and this prevents me from enabling multi-sampling.<br></div><div><br></div><div>Very grateful for any advice from experts on the OpenGL2 backend, as I really need to get this working and move on.<br><br></div><div>I'm attaching my vtk_widget2.py, which shows how I set up rendering into the QOpenGLWidget. Rendering of the cone example at the bottom works, it's just when I'm trying volume rendering using vtkGPUVolumeRayCastMapper that I get the above error.<span class=""><font color="#888888"><br></font></span></div><span class=""><font color="#888888"><div><br></div><div>Elvis<br><br></div></font></span><div><div class="h5"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span><font color="#888888"><br></font></span></div><span><font color="#888888"><div>Elvis<br> <br></div></font></span><div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div><div><div><div><div><br></div>I do however have two problems (indicated by "FIXME:"s in the code below):<br><br></div>1. When I try to call vtkOpenGLRenderWindow.OpenGLInitState when handling the render window StartEvent (commented out below), similar to how QVTKWidget2 does, I get a segmentation fault:<br><br>(gdb) bt<br>#0  0x0000000000000000 in ?? ()<br>#1  0x00007fffd8ad13b9 in vtkOpenGLRenderWindow::OpenGLInitState() () from /usr/lib/libvtkRenderingOpenGL2.so.1<br>#2  0x00007fffd8de8479 in ?? () from /usr/lib/libvtkRenderingOpenGL2Python35D.so.1<br>#3  0x00007ffff79ba5e9 in PyCFunction_Call () from /usr/lib/libpython3.5m.so.1.0<br>#4  0x00007ffff7a325f1 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#5  0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#6  0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#7  0x00007ffff799db98 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#8  0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#9  0x00007ffff7989d64 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#10 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#11 0x00007ffff7a2a457 in PyEval_CallObjectWithKeywords () from /usr/lib/libpython3.5m.so.1.0<br>#12 0x00007fffe8d905a0 in vtkPythonCommand::Execute(vtkObject*, unsigned long, void*) () from /usr/lib/libvtkWrappingPython35Core.so.1<br>#13 0x00007fffe89ac196 in ?? () from /usr/lib/libvtkCommonCore.so.1<br>#14 0x00007fffdf022a0f in vtkRenderWindow::Render() () from /usr/lib/libvtkRenderingCore.so.1<br>#15 0x00007fffd8ad4461 in vtkOpenGLRenderWindow::Render() () from /usr/lib/libvtkRenderingOpenGL2.so.1<br>#16 0x00007fffdf027498 in vtkRenderWindowInteractor::Start() () from /usr/lib/libvtkRenderingCore.so.1<br>#17 0x00007fffdf3ee789 in ?? () from /usr/lib/libvtkRenderingCorePython35D.so.1<br>#18 0x00007ffff79ba5e9 in PyCFunction_Call () from /usr/lib/libpython3.5m.so.1.0<br>#19 0x00007ffff7a325f1 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#20 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#21 0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#22 0x00007ffff799db98 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#23 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#24 0x00007ffff7989d64 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#25 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#26 0x00007ffff79cfa10 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#27 0x00007ffff79cdde6 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#28 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#29 0x00007ffff7a2c4bc in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#30 0x00007ffff7a32942 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#31 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#32 0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#33 0x00007ffff7a33aeb in PyEval_EvalCode () from /usr/lib/libpython3.5m.so.1.0<br>#34 0x00007ffff7a2802d in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#35 0x00007ffff79ba5e9 in PyCFunction_Call () from /usr/lib/libpython3.5m.so.1.0<br>#36 0x00007ffff7a325f1 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#37 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#38 0x00007ffff7a306e0 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#39 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#40 0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#41 0x00007ffff799db98 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#42 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#43 0x00007ffff7a6af01 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#44 0x00007ffff7a6b7dc in Py_Main () from /usr/lib/libpython3.5m.so.1.0<br>#45 0x0000000000400ae7 in main ()<br>(gdb)<br><br></div>Sorry for the lack of debugging symbols, but before I recompile VTK with debugging symbols, I thought I'd ask if anyone has an idea what may be the reason for the crash? I haven't seen any adverse effects from not calling this function, but I suspect something is broken? (how can I test?)<br><br></div>2. I can't seem to find a way to properly implement the WindowIsCurrentEvent, WindowIsDirectEvent and WindowSupportsOpenGLEvent render window events. E.g. (from below):<br><br>    def _onWindowIsCurrentEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowIsDirectEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowSupportsOpenGLEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br></div>The callData is a bool* and the handler is expected to write a bool to the pointed memory. I can't see that there's any way to do this from Python (is it possible with ctypes somehow?).<br><br></div>So far I haven't seen any adverse effects from not implementing these three events correctly, but expect something to be broken..?<br><br></div>Thankful for any advice on these two issues, and it would be great if someone could try out the example, with the<br><br>    # self.renderWindow.OpenGLInitState()  # FIXME: Segfaults :(<br><br></div>line uncommented, to confirm the segfault I'm seeing.<br><br></div>Cheers,<br></div>Elvis<br><br><br>from PyQt5.QtCore import Qt, QTimer, QEvent, QSize<br>from PyQt5.QtGui import QSurfaceFormat<br>from PyQt5.QtWidgets import QWidget, QOpenGLWidget<br><br>from vtk import vtkGenericOpenGLRenderWindow<br>from vtk import vtkGenericRenderWindowInteractor<br>from vtk import vtkCommand<br>from vtk import vtkRenderer<br><br>from vtk import VTK_CURSOR_DEFAULT, VTK_CURSOR_ARROW, VTK_CURSOR_SIZENE<br>from vtk import VTK_CURSOR_SIZENW, VTK_CURSOR_SIZESW, VTK_CURSOR_SIZESE<br>from vtk import VTK_CURSOR_SIZENS, VTK_CURSOR_SIZEWE, VTK_CURSOR_SIZEALL<br>from vtk import VTK_CURSOR_HAND, VTK_CURSOR_CROSSHAIR<br><br><br>class VTKWidget(QOpenGLWidget):<br><br>    def __init__(self, surfaceFormat=QSurfaceFormat.defaultFormat(), *args, **kwargs):<br>        super().__init__(*args, **kwargs)<br><br>        # Request OpenGL 3.2 compatibility profile and enable multi-sampling<br>        surfaceFormat.setMajorVersion(3)<br>        surfaceFormat.setMinorVersion(2)<br>        surfaceFormat.setProfile(QSurfaceFormat.CompatibilityProfile)<br>        surfaceFormat.setSamples(8)<br>        self.setFormat(surfaceFormat)<br><br>        # Create render window<br>        self.renderWindow = vtkGenericOpenGLRenderWindow()<br>        self.renderWindow.SetSize(self.width(), self.height())<br>        self.renderWindow.SetPosition(self.x(), self.y())<br><br>        self.renderWindow.AddObserver(vtkCommand.StartEvent,<br>                                      self._onStartEvent)<br>        self.renderWindow.AddObserver(vtkCommand.EndEvent,<br>                                      self._onEndEvent)<br>        self.renderWindow.AddObserver(vtkCommand.CursorChangedEvent,<br>                                      self._onCursorChangedEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowMakeCurrentEvent,<br>                                      self._onWindowMakeCurrentEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowIsCurrentEvent,<br>                                      self._onWindowIsCurrentEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowFrameEvent,<br>                                      self._onWindowFrameEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowIsDirectEvent,<br>                                      self._onWindowIsDirectEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowSupportsOpenGLEvent,<br>                                      self._onWindowSupportsOpenGLEvent)<br><br>        # Create interactor<br>        self.interactor = vtkGenericRenderWindowInteractor()<br>        self.interactor.SetRenderWindow(self.renderWindow)<br>        self.interactor.SetSize(self.width(), self.height())<br>        self.interactor.AddObserver(vtkCommand.CreateTimerEvent,<br>                                    lambda *_: self._timer.start(10))<br>        self.interactor.AddObserver(vtkCommand.DestroyTimerEvent,<br>                                    lambda *_: self._timer.stop())<br>        self.interactor.Start()<br><br>        # Create renderer<br>        self.renderer = vtkRenderer()<br>        self.renderWindow.AddRenderer(self.renderer)<br><br>        # Timer for the interactor<br>        self._timer = QTimer(self)<br>        self._timer.timeout.connect(self.interactor.TimerEvent)<br><br>        # Some tracked input state<br>        self._pressedButton = Qt.NoButton<br>        self._lastMouseX = 0<br>        self._lastMouseY = 0<br>        self._lastModifiers = Qt.NoModifier<br>        self._lastButtons = Qt.NoButton<br>        self._wheelDelta = 0<br><br>        # Finalize render window before we're destroyed<br>        self._hidden = QWidget(self)<br>        self._hidden.hide()<br>        self._hidden.destroyed.connect(self.renderWindow.Finalize)<br><br>    #<br>    # Handle VTK render window events<br>    #<br><br>    def _onStartEvent(self, *_):<br>        self.makeCurrent()<br>        self.renderWindow.PushState()<br>        # self.renderWindow.OpenGLInitState()  # FIXME: Segfaults :(<br><br>    def _onEndEvent(self, *_):<br>        self.renderWindow.PopState()<br><br>    def _onWindowMakeCurrentEvent(self, *_):<br>        pass  # Handled automatically by QOpenGLWidget<br><br>    def _onWindowIsCurrentEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowIsDirectEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowSupportsOpenGLEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowFrameEvent(self, *_):<br>        if self.renderWindow.GetSwapBuffers():<br>            self.update()<br><br>    def _onCursorChangedEvent(self):<br><br>        def showCursor():<br>            vtkCursor = self.renderWindow.GetCurrentCursor()<br>            qtCursor = VTKWidget._cursors.get(vtkCursor, Qt.ArrowCursor)<br>            self.setCursor(qtCursor)<br><br>        # Defer until cursor has actually changed<br>        QTimer.singleShot(0, showCursor)<br><br>    #<br>    # Implement QOpenGLWidget functions<br>    #<br><br>    def initializeGL(self):<br>        self.renderWindow.OpenGLInitContext()<br><br>    def paintGL(self):<br>        self.interactor.Render()<br><br>    def resizeGL(self, width, height):<br>        self.renderWindow.SetSize(width, height)<br>        self.interactor.SetSize(width, height)<br>        self.interactor.ConfigureEvent()<br><br>    #<br>    # Handle QWidget events<br>    #<br><br>    def closeEvent(self, _):<br>        self.renderWindow.Finalize()<br><br>    def sizeHint(self):<br>        return QSize(400, 400)<br><br>    def moveEvent(self, event):<br>        super().moveEvent(event)<br>        self.renderWindow.SetPosition(self.x(), self.y())<br><br>    def enterEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, chr(0), 0, None)<br>        self.interactor.EnterEvent()<br><br>    def leaveEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, chr(0), 0, None)<br>        self.interactor.LeaveEvent()<br><br>    def mousePressEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        repeat = 1 if event.type() == QEvent.MouseButtonDblClick else 0<br>        self.interactor.SetEventInformationFlipY(event.x(), event.y(), ctrl, shift,<br>                                                 chr(0), repeat, None)<br><br>        self._pressedButton = event.button()<br><br>        if self._pressedButton == Qt.LeftButton:<br>            self.interactor.LeftButtonPressEvent()<br>        elif self._pressedButton == Qt.RightButton:<br>            self.interactor.RightButtonPressEvent()<br>        elif self._pressedButton == Qt.MidButton:<br>            self.interactor.MiddleButtonPressEvent()<br><br>    def mouseReleaseEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(event.x(), event.y(), ctrl, shift,<br>                                                 chr(0), 0, None)<br><br>        if self._pressedButton == Qt.LeftButton:<br>            self.interactor.LeftButtonReleaseEvent()<br>        elif self._pressedButton == Qt.RightButton:<br>            self.interactor.RightButtonReleaseEvent()<br>        elif self._pressedButton == Qt.MidButton:<br>            self.interactor.MiddleButtonReleaseEvent()<br><br>        self._pressedButton = Qt.NoButton<br><br>    def mouseMoveEvent(self, event):<br>        self._lastModifiers = event.modifiers()<br>        self._lastButtons = event.buttons()<br>        self._lastMouseX = event.x()<br>        self._lastMouseY = event.y()<br><br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(event.x(), event.y(), ctrl, shift,<br>                                                 chr(0), 0, None)<br>        self.interactor.MouseMoveEvent()<br><br>    def keyPressEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        key = str(event.text()) if event.key() < 256 else chr(0)<br>        keySym = VTKWidget._qtKeyToKeySymbol(event.key())<br><br>        if shift and len(keySym) == 1 and keySym.isalpha():<br>            keySym = keySym.upper()<br><br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, key, 0, keySym)<br>        self.interactor.KeyPressEvent()<br>        self.interactor.CharEvent()<br><br>    def keyReleaseEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        key = chr(event.key()) if event.key() < 256 else chr(0)<br><br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, key, 0, None)<br>        self.interactor.KeyReleaseEvent()<br><br>    def wheelEvent(self, event):<br>        self._wheelDelta += event.angleDelta().y()<br><br>        if self._wheelDelta >= 120:<br>            self.interactor.MouseWheelForwardEvent()<br>            self._wheelDelta = 0<br>        elif self._wheelDelta <= -120:<br>            self.interactor.MouseWheelBackwardEvent()<br>            self._wheelDelta = 0<br><br>    def _modifiers(self, event):<br>        ctrl = shift = False<br><br>        if hasattr(event, 'modifiers'):<br>            if event.modifiers() & Qt.ShiftModifier:<br>                shift = True<br>            if event.modifiers() & Qt.ControlModifier:<br>                ctrl = True<br>        else:<br>            if self._lastModifiers & Qt.ShiftModifier:<br>                shift = True<br>            if self._lastModifiers & Qt.ControlModifier:<br>                ctrl = True<br><br>        return ctrl, shift<br><br>    @classmethod<br>    def _qtKeyToKeySymbol(cls, key):<br>        if key not in VTKWidget._keySymbols:<br>            return None<br>        return VTKWidget._keySymbols[key]<br><br>    # Maps VTK cursors to Qt cursors<br>    _cursors = {<br>        VTK_CURSOR_DEFAULT: Qt.ArrowCursor,<br>        VTK_CURSOR_ARROW: Qt.ArrowCursor,<br>        VTK_CURSOR_SIZENE: Qt.SizeBDiagCursor,<br>        VTK_CURSOR_SIZENW: Qt.SizeFDiagCursor,<br>        VTK_CURSOR_SIZESW: Qt.SizeBDiagCursor,<br>        VTK_CURSOR_SIZESE: Qt.SizeFDiagCursor,<br>        VTK_CURSOR_SIZENS: Qt.SizeVerCursor,<br>        VTK_CURSOR_SIZEWE: Qt.SizeHorCursor,<br>        VTK_CURSOR_SIZEALL: Qt.SizeAllCursor,<br>        VTK_CURSOR_HAND: Qt.PointingHandCursor,<br>        VTK_CURSOR_CROSSHAIR: Qt.CrossCursor<br>    }<br><br>    # Maps Qt keys to VTK key symbols<br>    _keySymbols = {<br>        Qt.Key_Backspace: 'BackSpace',<br>        Qt.Key_Tab: 'Tab',<br>        Qt.Key_Backtab: 'Tab',<br>        # Qt.Key_Clear : 'Clear',<br>        Qt.Key_Return: 'Return',<br>        Qt.Key_Enter: 'Return',<br>        Qt.Key_Shift: 'Shift_L',<br>        Qt.Key_Control: 'Control_L',<br>        Qt.Key_Alt: 'Alt_L',<br>        Qt.Key_Pause: 'Pause',<br>        Qt.Key_CapsLock: 'Caps_Lock',<br>        Qt.Key_Escape: 'Escape',<br>        Qt.Key_Space: 'space',<br>        # Qt.Key_Prior : 'Prior',<br>        # Qt.Key_Next : 'Next',<br>        Qt.Key_End: 'End',<br>        Qt.Key_Home: 'Home',<br>        Qt.Key_Left: 'Left',<br>        Qt.Key_Up: 'Up',<br>        Qt.Key_Right: 'Right',<br>        Qt.Key_Down: 'Down',<br>        Qt.Key_SysReq: 'Snapshot',<br>        Qt.Key_Insert: 'Insert',<br>        Qt.Key_Delete: 'Delete',<br>        Qt.Key_Help: 'Help',<br>        Qt.Key_0: '0',<br>        Qt.Key_1: '1',<br>        Qt.Key_2: '2',<br>        Qt.Key_3: '3',<br>        Qt.Key_4: '4',<br>        Qt.Key_5: '5',<br>        Qt.Key_6: '6',<br>        Qt.Key_7: '7',<br>        Qt.Key_8: '8',<br>        Qt.Key_9: '9',<br>        Qt.Key_A: 'a',<br>        Qt.Key_B: 'b',<br>        Qt.Key_C: 'c',<br>        Qt.Key_D: 'd',<br>        Qt.Key_E: 'e',<br>        Qt.Key_F: 'f',<br>        Qt.Key_G: 'g',<br>        Qt.Key_H: 'h',<br>        Qt.Key_I: 'i',<br>        Qt.Key_J: 'j',<br>        Qt.Key_K: 'k',<br>        Qt.Key_L: 'l',<br>        Qt.Key_M: 'm',<br>        Qt.Key_N: 'n',<br>        Qt.Key_O: 'o',<br>        Qt.Key_P: 'p',<br>        Qt.Key_Q: 'q',<br>        Qt.Key_R: 'r',<br>        Qt.Key_S: 's',<br>        Qt.Key_T: 't',<br>        Qt.Key_U: 'u',<br>        Qt.Key_V: 'v',<br>        Qt.Key_W: 'w',<br>        Qt.Key_X: 'x',<br>        Qt.Key_Y: 'y',<br>        Qt.Key_Z: 'z',<br>        Qt.Key_Asterisk: 'asterisk',<br>        Qt.Key_Plus: 'plus',<br>        Qt.Key_Minus: 'minus',<br>        Qt.Key_Period: 'period',<br>        Qt.Key_Slash: 'slash',<br>        Qt.Key_F1: 'F1',<br>        Qt.Key_F2: 'F2',<br>        Qt.Key_F3: 'F3',<br>        Qt.Key_F4: 'F4',<br>        Qt.Key_F5: 'F5',<br>        Qt.Key_F6: 'F6',<br>        Qt.Key_F7: 'F7',<br>        Qt.Key_F8: 'F8',<br>        Qt.Key_F9: 'F9',<br>        Qt.Key_F10: 'F10',<br>        Qt.Key_F11: 'F11',<br>        Qt.Key_F12: 'F12',<br>        Qt.Key_F13: 'F13',<br>        Qt.Key_F14: 'F14',<br>        Qt.Key_F15: 'F15',<br>        Qt.Key_F16: 'F16',<br>        Qt.Key_F17: 'F17',<br>        Qt.Key_F18: 'F18',<br>        Qt.Key_F19: 'F19',<br>        Qt.Key_F20: 'F20',<br>        Qt.Key_F21: 'F21',<br>        Qt.Key_F22: 'F22',<br>        Qt.Key_F23: 'F23',<br>        Qt.Key_F24: 'F24',<br>        Qt.Key_NumLock: 'Num_Lock',<br>        Qt.Key_ScrollLock: 'Scroll_Lock'<br>    }<br><br>def example():<br>    #<br>    # Try out VTKWidget by showing a couple of cones<br>    #<br>    from sys import argv, exit<br>    from PyQt5.QtWidgets import QApplication, QVBoxLayout<br>    from vtk import vtkConeSource, vtkPolyDataMapper, vtkActor<br><br>    app = QApplication(argv)<br><br>    layout = QVBoxLayout()<br><br>    for i in range(2):<br>        widget = VTKWidget()<br><br>        coneSource = vtkConeSource()<br>        coneSource.SetResolution(8)<br><br>        coneMapper = vtkPolyDataMapper()<br>        coneMapper.SetInputConnection(coneSource.GetOutputPort())<br><br>        coneActor = vtkActor()<br>        coneActor.SetMapper(coneMapper)<br><br>        widget.renderer.AddActor(coneActor)<br><br>        layout.addWidget(widget)<br><br>    container = QWidget()<br>    container.setLayout(layout)<br>    container.show()<br><br>    exit(app.exec_())<br><br><br>if __name__ == '__main__':<br>    example()<br><br></div>
</blockquote></div></div></div><br></div></div>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div>