QVTKRenderWindowInteractor.py 8.68 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"""
A simple VTK input file for PyQt, the qt bindings for python.
See http://www.trolltech.com for qt documentation, and
http://www.thekompany.com for the qt python bindings.

This class is based on the vtkGenericRenderWindowInteractor and is
therefore fairly powerful.  It should also play nicely with the
vtk3DWidget code.

Created by Prabhu Ramachandran, May 2002
Based on David Gobbi's QVTKRenderWidget.py
"""

"""
This class works only with the UNIX version of Qt.
It does not work under the Win32 version of Qt.

Depending on the OpenGL graphics drivers, it may not
be possible to have more than one QVTKRenderWidget
per application.

In short, this class is experimental.
"""

import math, os, sys
import qt
import vtk

class QVTKRenderWindowInteractor(qt.QWidget):

    """ A QVTKRenderWindowInteractor for Python and Qt.  Uses a
    vtkGenericRenderWindowInteractor to handle the interactions.  Use
    GetRenderWindow() to get the vtkRenderWindow.  Create with the
    keyword stereo=1 in order to generate a stereo-capable window.
    """
    
    def __init__(self, parent=None, name=None, *args, **kw):

        # the current button
        self._ActiveButton = 0

        # private attributes
        self.__oldFocus = None
        self.__saveX = 0
        self.__saveY = 0
        self.__saveState = 0
        self.__connected = 0  # is QT->VTK connection done?

        # do special handling of some keywords:
        # stereo, rw
        
        stereo = 0
        
        if kw.has_key('stereo'):
            if kw['stereo']:
                stereo = 1
            del kw['stereo']

        rw = None

        if kw.has_key('rw'):
            rw = kw['rw']
            del kw['rw']

        # create qt-level widget
        apply(qt.QWidget.__init__, (self,parent,name) + args, kw)

        if rw: # user-supplied render window
            self._RenderWindow = rw
        else:
            self._RenderWindow = vtk.vtkRenderWindow()

        if stereo: # stereo mode
            self._RenderWindow.StereoCapableWindowOn()
            self._RenderWindow.SetStereoTypeToCrystalEyes()

        self._Iren = vtk.vtkGenericRenderWindowInteractor()
        self._Iren.SetRenderWindow(self._RenderWindow)

        # do all the necessary qt setup
        self.setBackgroundMode(2) # NoBackground
        self.setMouseTracking(1) # get all mouse events
        self.setFocusPolicy(2) # ClickFocus
        if parent == None:
            self.show()
        
        if self.isVisible():
            if self.__connected == 0:
                size = self.size()
                self._RenderWindow.SetSize(size.width(),size.height())
                self._RenderWindow.SetWindowInfo(str(self.winId()))
                self.__connected = 1

        self._Timer = qt.QTimer(self, 'timer handler')
        self.connect(self._Timer, qt.SIGNAL('timeout()'),
                     self.TimerEvent)

        self._Iren.AddObserver('CreateTimerEvent', self.CreateTimer)
        self._Iren.AddObserver('DestroyTimerEvent', self.DestroyTimer)
        
    def __getattr__(self, attr):        
        """Makes the object behave like a
        vtkGenericRenderWindowInteractor"""
        if attr == '__vtk__':
            return lambda t=self._Iren: t
        elif hasattr(self._Iren, attr):
            return getattr(self._Iren, attr)
        elif hasattr(qt.QWidget, attr):
            return getattr(self.sipThis, attr)
        else:
            raise AttributeError, self.__class__.__name__ + \
                  " has no attribute named " + attr

    def CreateTimer(self, obj, evt):
        self._Timer.start(10)

    def DestroyTimer(self, obj, evt):
        self._Timer.stop()
        return 1

    def TimerEvent(self):
        self._Iren.TimerEvent()

    def paintEvent(self,ev):
        if self.isVisible():
            if self.__connected == 0:
                size = self.size()
                self._Iren.SetSize(size.width(),size.height())
                self._RenderWindow.SetWindowInfo(str(self.winId()))
                self._Iren.ConfigureEvent()
                self.__connected = 1
        if self.__connected:
            self.Render()

    def resizeEvent(self,ev):
        size = self.size()
        self._Iren.SetSize(size.width(),size.height())
        self._Iren.ConfigureEvent()
        self.repaint()

141
142
143
144
145
146
147
148
149
150
151
152
153
154
    def _GetCtrlShift(self, ev):
        ctrl, shift = 0, 0
        if hasattr(ev, 'state'):
            if (ev.state() & 8):
                shift = 1
            if (ev.state() & 16):
                ctrl = 1
        elif self.__saveState:
            if (self.__saveState & 8):
                shift = 1
            if (self.__saveState & 16):
                ctrl = 1            
        return ctrl, shift

155
156
157
158
    def enterEvent(self,ev):
        if not self.hasFocus():
            self.__oldFocus = self.focusWidget()
            self.setFocus()
159
        ctrl, shift = self._GetCtrlShift(ev)
160
        self._Iren.SetEventInformationFlipY(self.__saveX, self.__saveY,
161
                                            ctrl, shift, chr(0), 0, None)
162
163
164
165
166
167
        self._Iren.EnterEvent()

    def leaveEvent(self,ev):
        if (self.__saveState & 0x7) == 0 and self.__oldFocus:
            self.__oldFocus.setFocus()
            self.__oldFocus = None
168
        ctrl, shift = self._GetCtrlShift(ev)
169
        self._Iren.SetEventInformationFlipY(self.__saveX, self.__saveY,
170
                                            ctrl, shift, chr(0), 0, None)
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
        self._Iren.LeaveEvent()

    def mousePressEvent(self,ev):
        ctrl, shift = self._GetCtrlShift(ev)
        self._Iren.SetEventInformationFlipY(ev.x(), ev.y(),
                                            ctrl, shift, chr(0), 0, None)

        self._ActiveButton = 0
        if ev.button() == 1:
            self._Iren.LeftButtonPressEvent()
            self._ActiveButton = 'Left'
        elif ev.button() == 2:
            self._Iren.RightButtonPressEvent()
            self._ActiveButton = 'Right'
        elif ev.button() == 4:
            self._Iren.MiddleButtonPressEvent()
            self._ActiveButton = 'Middle'

    def mouseReleaseEvent(self,ev):
        ctrl, shift = self._GetCtrlShift(ev)
        self._Iren.SetEventInformationFlipY(ev.x(), ev.y(),
                                            ctrl, shift, chr(0), 0, None)
        
        if self._ActiveButton == 'Right':
            self._Iren.RightButtonReleaseEvent()
        elif self._ActiveButton == 'Left':
            self._Iren.LeftButtonReleaseEvent()
        elif self._ActiveButton == 'Middle':
            self._Iren.MiddleButtonReleaseEvent()

    def mouseMoveEvent(self,ev):
        self.__saveState = ev.state()
        self.__saveX = ev.x()
        self.__saveY = ev.y()
205
        ctrl, shift = self._GetCtrlShift(ev)
206
        self._Iren.SetEventInformationFlipY(ev.x(), ev.y(),
207
                                            ctrl, shift, chr(0), 0, None)
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
        self._Iren.MouseMoveEvent()

    def keyPressEvent(self,ev):
        ctrl, shift = self._GetCtrlShift(ev)
        key = chr(0)
        if ev.key() < 256:
            key = chr(ev.key())

        self._Iren.SetEventInformationFlipY(self.__saveX, self.__saveY,
                                            ctrl, shift, key, 0,
                                            None)
        self._Iren.KeyPressEvent()
        self._Iren.CharEvent()
        
    def keyReleaseEvent(self,ev):
        ctrl, shift = self._GetCtrlShift(ev)
        key = chr(0)
        if ev.key() < 256:
            key = chr(ev.key())

        self._Iren.SetEventInformationFlipY(self.__saveX, self.__saveY,
                                            ctrl, shift, key, 0,
                                            None)
        self._Iren.KeyReleaseEvent()

    def GetRenderWindow(self):
        return self._RenderWindow

    def Render(self):
        self._RenderWindow.Render()

#----------------------------------------------------------------------------  
def QVTKRenderWidgetConeExample():
    """Like it says, just a simple example
    """
    # every QT app needs an app
    app = qt.QApplication(['QVTKRenderWindowInteractor'])

    # create the widget
    widget = QVTKRenderWindowInteractor()
    widget.Initialize()
    widget.Start()
    # if you dont want the 'q' key to exit comment this.
    widget.SetExitMethod(app.quit)

    ren = vtk.vtkRenderer()
    widget.GetRenderWindow().AddRenderer(ren)

    cone = vtk.vtkConeSource()
    cone.SetResolution(8)
    
    coneMapper = vtk.vtkPolyDataMapper()
    coneMapper.SetInput(cone.GetOutput())
    
    coneActor = vtk.vtkActor()
    coneActor.SetMapper(coneMapper)

    ren.AddActor(coneActor)

    # show the widget
    widget.show()
    # close the application when window is closed
    app.setMainWidget(widget)
    # start event processing
    app.exec_loop()
    
if __name__ == "__main__":
    QVTKRenderWidgetConeExample()