vtkTkRenderWindowInteractor.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. """
  2. A fully functional VTK widget for tkinter that uses
  3. vtkGenericRenderWindowInteractor. The widget is called
  4. vtkTkRenderWindowInteractor. The initialization part of this code is
  5. similar to that of the vtkTkRenderWidget.
  6. Created by Prabhu Ramachandran, April 2002
  7. """
  8. from __future__ import absolute_import
  9. import math, os, sys
  10. from vtkmodules.vtkRenderingCore import vtkRenderWindow
  11. from vtkmodules.vtkRenderingUI import vtkGenericRenderWindowInteractor
  12. if sys.hexversion < 0x03000000:
  13. # for Python2
  14. import Tkinter as tkinter
  15. else:
  16. # for Python3
  17. import tkinter
  18. from .vtkLoadPythonTkWidgets import vtkLoadPythonTkWidgets
  19. class vtkTkRenderWindowInteractor(tkinter.Widget):
  20. """ A vtkTkRenderWidndowInteractor for Python.
  21. Use GetRenderWindow() to get the vtkRenderWindow.
  22. Create with the keyword stereo=1 in order to generate a
  23. stereo-capable window.
  24. Create with the keyword focus_on_enter=1 to enable
  25. focus-follows-mouse. The default is for a click-to-focus mode.
  26. __getattr__ is used to make the widget also behave like a
  27. vtkGenericRenderWindowInteractor.
  28. """
  29. def __init__(self, master, cnf={}, **kw):
  30. """
  31. Constructor.
  32. Keyword arguments:
  33. rw -- Use passed render window instead of creating a new one.
  34. stereo -- If True, generate a stereo-capable window.
  35. Defaults to False.
  36. focus_on_enter -- If True, use a focus-follows-mouse mode.
  37. Defaults to False where the widget will use a click-to-focus
  38. mode.
  39. """
  40. # load the necessary extensions into tk
  41. vtkLoadPythonTkWidgets(master.tk)
  42. try: # check to see if a render window was specified
  43. renderWindow = kw['rw']
  44. except KeyError:
  45. renderWindow = vtkRenderWindow()
  46. try: # was a stereo rendering context requested?
  47. if kw['stereo']:
  48. renderWindow.StereoCapableWindowOn()
  49. del kw['stereo']
  50. except KeyError:
  51. pass
  52. # check if focus should follow mouse
  53. if kw.get('focus_on_enter'):
  54. self._FocusOnEnter = 1
  55. del kw['focus_on_enter']
  56. else:
  57. self._FocusOnEnter = 0
  58. kw['rw'] = renderWindow.GetAddressAsString("vtkRenderWindow")
  59. tkinter.Widget.__init__(self, master, 'vtkTkRenderWidget', cnf, kw)
  60. self._Iren = vtkGenericRenderWindowInteractor()
  61. self._Iren.SetRenderWindow(self._RenderWindow)
  62. self._Iren.AddObserver('CreateTimerEvent', self.CreateTimer)
  63. self._Iren.AddObserver('DestroyTimerEvent', self.DestroyTimer)
  64. self._OldFocus = None
  65. # private attributes
  66. self.__InExpose = 0
  67. # create the Tk bindings
  68. self.BindEvents()
  69. #self.tk_focusFollowsMouse()
  70. def __getattr__(self, attr):
  71. # because the tk part of vtkTkRenderWidget must have
  72. # the only remaining reference to the RenderWindow when
  73. # it is destroyed, we can't actually store the RenderWindow
  74. # as an attribute but instead have to get it from the tk-side
  75. if attr == '__vtk__':
  76. return lambda t=self._Iren: t
  77. elif attr == '_RenderWindow':
  78. return self.GetRenderWindow()
  79. elif hasattr(self._Iren, attr):
  80. return getattr(self._Iren, attr)
  81. else:
  82. raise AttributeError(self.__class__.__name__ +
  83. " has no attribute named " + attr)
  84. def BindEvents(self):
  85. """ Bind all the events. """
  86. self.bind("<Motion>",
  87. lambda e, s=self: s.MouseMoveEvent(e, 0, 0))
  88. self.bind("<Control-Motion>",
  89. lambda e, s=self: s.MouseMoveEvent(e, 1, 0))
  90. self.bind("<Shift-Motion>",
  91. lambda e, s=self: s.MouseMoveEvent(e, 1, 1))
  92. self.bind("<Control-Shift-Motion>",
  93. lambda e, s=self: s.MouseMoveEvent(e, 0, 1))
  94. # Left Button
  95. self.bind("<ButtonPress-1>",
  96. lambda e, s=self: s.LeftButtonPressEvent(e, 0, 0))
  97. self.bind("<Control-ButtonPress-1>",
  98. lambda e, s=self: s.LeftButtonPressEvent(e, 1, 0))
  99. self.bind("<Shift-ButtonPress-1>",
  100. lambda e, s=self: s.LeftButtonPressEvent(e, 0, 1))
  101. self.bind("<Control-Shift-ButtonPress-1>",
  102. lambda e, s=self: s.LeftButtonPressEvent(e, 1, 1))
  103. self.bind("<ButtonRelease-1>",
  104. lambda e, s=self: s.LeftButtonReleaseEvent(e, 0, 0))
  105. self.bind("<Control-ButtonRelease-1>",
  106. lambda e, s=self: s.LeftButtonReleaseEvent(e, 1, 0))
  107. self.bind("<Shift-ButtonRelease-1>",
  108. lambda e, s=self: s.LeftButtonReleaseEvent(e, 0, 1))
  109. self.bind("<Control-Shift-ButtonRelease-1>",
  110. lambda e, s=self: s.LeftButtonReleaseEvent(e, 1, 1))
  111. # Middle Button
  112. self.bind("<ButtonPress-2>",
  113. lambda e, s=self: s.MiddleButtonPressEvent(e, 0, 0))
  114. self.bind("<Control-ButtonPress-2>",
  115. lambda e, s=self: s.MiddleButtonPressEvent(e, 1, 0))
  116. self.bind("<Shift-ButtonPress-2>",
  117. lambda e, s=self: s.MiddleButtonPressEvent(e, 0, 1))
  118. self.bind("<Control-Shift-ButtonPress-2>",
  119. lambda e, s=self: s.MiddleButtonPressEvent(e, 1, 1))
  120. self.bind("<ButtonRelease-2>",
  121. lambda e, s=self: s.MiddleButtonReleaseEvent(e, 0, 0))
  122. self.bind("<Control-ButtonRelease-2>",
  123. lambda e, s=self: s.MiddleButtonReleaseEvent(e, 1, 0))
  124. self.bind("<Shift-ButtonRelease-2>",
  125. lambda e, s=self: s.MiddleButtonReleaseEvent(e, 0, 1))
  126. self.bind("<Control-Shift-ButtonRelease-2>",
  127. lambda e, s=self: s.MiddleButtonReleaseEvent(e, 1, 1))
  128. # Right Button
  129. self.bind("<ButtonPress-3>",
  130. lambda e, s=self: s.RightButtonPressEvent(e, 0, 0))
  131. self.bind("<Control-ButtonPress-3>",
  132. lambda e, s=self: s.RightButtonPressEvent(e, 1, 0))
  133. self.bind("<Shift-ButtonPress-3>",
  134. lambda e, s=self: s.RightButtonPressEvent(e, 0, 1))
  135. self.bind("<Control-Shift-ButtonPress-3>",
  136. lambda e, s=self: s.RightButtonPressEvent(e, 1, 1))
  137. self.bind("<ButtonRelease-3>",
  138. lambda e, s=self: s.RightButtonReleaseEvent(e, 0, 0))
  139. self.bind("<Control-ButtonRelease-3>",
  140. lambda e, s=self: s.RightButtonReleaseEvent(e, 1, 0))
  141. self.bind("<Shift-ButtonRelease-3>",
  142. lambda e, s=self: s.RightButtonReleaseEvent(e, 0, 1))
  143. self.bind("<Control-Shift-ButtonRelease-3>",
  144. lambda e, s=self: s.RightButtonReleaseEvent(e, 1, 1))
  145. if sys.platform == 'win32':
  146. self.bind("<MouseWheel>",
  147. lambda e, s=self: s.MouseWheelEvent(e, 0, 0))
  148. self.bind("<Control-MouseWheel>",
  149. lambda e, s=self: s.MouseWheelEvent(e, 1, 0))
  150. self.bind("<Shift-MouseWheel>",
  151. lambda e, s=self: s.MouseWheelEvent(e, 0, 1))
  152. self.bind("<Control-Shift-MouseWheel>",
  153. lambda e, s=self: s.MouseWheelEvent(e, 1, 1))
  154. else:
  155. # Mouse wheel forward event
  156. self.bind("<ButtonPress-4>",
  157. lambda e, s=self: s.MouseWheelForwardEvent(e, 0, 0))
  158. self.bind("<Control-ButtonPress-4>",
  159. lambda e, s=self: s.MouseWheelForwardEvent(e, 1, 0))
  160. self.bind("<Shift-ButtonPress-4>",
  161. lambda e, s=self: s.MouseWheelForwardEvent(e, 0, 1))
  162. self.bind("<Control-Shift-ButtonPress-4>",
  163. lambda e, s=self: s.MouseWheelForwardEvent(e, 1, 1))
  164. # Mouse wheel backward event
  165. self.bind("<ButtonPress-5>",
  166. lambda e, s=self: s.MouseWheelBackwardEvent(e, 0, 0))
  167. self.bind("<Control-ButtonPress-5>",
  168. lambda e, s=self: s.MouseWheelBackwardEvent(e, 1, 0))
  169. self.bind("<Shift-ButtonPress-5>",
  170. lambda e, s=self: s.MouseWheelBackwardEvent(e, 0, 1))
  171. self.bind("<Control-Shift-ButtonPress-5>",
  172. lambda e, s=self: s.MouseWheelBackwardEvent(e, 1, 1))
  173. # Key related events
  174. self.bind("<KeyPress>",
  175. lambda e, s=self: s.KeyPressEvent(e, 0, 0))
  176. self.bind("<Control-KeyPress>",
  177. lambda e, s=self: s.KeyPressEvent(e, 1, 0))
  178. self.bind("<Shift-KeyPress>",
  179. lambda e, s=self: s.KeyPressEvent(e, 0, 1))
  180. self.bind("<Control-Shift-KeyPress>",
  181. lambda e, s=self: s.KeyPressEvent(e, 1, 1))
  182. self.bind("<KeyRelease>",
  183. lambda e, s=self: s.KeyReleaseEvent(e, 0, 0))
  184. self.bind("<Control-KeyRelease>",
  185. lambda e, s=self: s.KeyReleaseEvent(e, 1, 0))
  186. self.bind("<Shift-KeyRelease>",
  187. lambda e, s=self: s.KeyReleaseEvent(e, 0, 1))
  188. self.bind("<Control-Shift-KeyRelease>",
  189. lambda e, s=self: s.KeyReleaseEvent(e, 1, 1))
  190. self.bind("<Enter>",
  191. lambda e, s=self: s.EnterEvent(e, 0, 0))
  192. self.bind("<Control-Enter>",
  193. lambda e, s=self: s.EnterEvent(e, 1, 0))
  194. self.bind("<Shift-Enter>",
  195. lambda e, s=self: s.EnterEvent(e, 0, 1))
  196. self.bind("<Control-Shift-Enter>",
  197. lambda e, s=self: s.EnterEvent(e, 1, 1))
  198. self.bind("<Leave>",
  199. lambda e, s=self: s.LeaveEvent(e, 0, 0))
  200. self.bind("<Control-Leave>",
  201. lambda e, s=self: s.LeaveEvent(e, 1, 0))
  202. self.bind("<Shift-Leave>",
  203. lambda e, s=self: s.LeaveEvent(e, 0, 1))
  204. self.bind("<Control-Shift-Leave>",
  205. lambda e, s=self: s.LeaveEvent(e, 1, 1))
  206. self.bind("<Configure>", self.ConfigureEvent)
  207. self.bind("<Expose>",lambda e,s=self: s.ExposeEvent())
  208. def CreateTimer(self, obj, evt):
  209. self.after(10, self._Iren.TimerEvent)
  210. def DestroyTimer(self, obj, event):
  211. """The timer is a one shot timer so will expire automatically."""
  212. return 1
  213. def _GrabFocus(self, enter=0):
  214. self._OldFocus=self.focus_get()
  215. self.focus()
  216. def MouseMoveEvent(self, event, ctrl, shift):
  217. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  218. shift, chr(0), 0, None)
  219. self._Iren.MouseMoveEvent()
  220. def LeftButtonPressEvent(self, event, ctrl, shift):
  221. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  222. shift, chr(0), 0, None)
  223. self._Iren.LeftButtonPressEvent()
  224. if not self._FocusOnEnter:
  225. self._GrabFocus()
  226. def LeftButtonReleaseEvent(self, event, ctrl, shift):
  227. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  228. shift, chr(0), 0, None)
  229. self._Iren.LeftButtonReleaseEvent()
  230. def MiddleButtonPressEvent(self, event, ctrl, shift):
  231. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  232. shift, chr(0), 0, None)
  233. self._Iren.MiddleButtonPressEvent()
  234. if not self._FocusOnEnter:
  235. self._GrabFocus()
  236. def MiddleButtonReleaseEvent(self, event, ctrl, shift):
  237. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  238. shift, chr(0), 0, None)
  239. self._Iren.MiddleButtonReleaseEvent()
  240. def RightButtonPressEvent(self, event, ctrl, shift):
  241. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  242. shift, chr(0), 0, None)
  243. self._Iren.RightButtonPressEvent()
  244. if not self._FocusOnEnter:
  245. self._GrabFocus()
  246. def RightButtonReleaseEvent(self, event, ctrl, shift):
  247. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  248. shift, chr(0), 0, None)
  249. self._Iren.RightButtonReleaseEvent()
  250. def MouseWheelEvent(self, event, ctrl, shift):
  251. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  252. shift, chr(0), 0, None)
  253. if event.delta > 0:
  254. self._Iren.MouseWheelForwardEvent()
  255. else:
  256. self._Iren.MouseWheelBackwardEvent()
  257. def MouseWheelForwardEvent(self, event, ctrl, shift):
  258. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  259. shift, chr(0), 0, None)
  260. self._Iren.MouseWheelForwardEvent()
  261. def MouseWheelBackwardEvent(self, event, ctrl, shift):
  262. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  263. shift, chr(0), 0, None)
  264. self._Iren.MouseWheelBackwardEvent()
  265. def KeyPressEvent(self, event, ctrl, shift):
  266. key = chr(0)
  267. if event.keysym_num < 256:
  268. key = chr(event.keysym_num)
  269. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  270. shift, key, 0, event.keysym)
  271. self._Iren.KeyPressEvent()
  272. self._Iren.CharEvent()
  273. def KeyReleaseEvent(self, event, ctrl, shift):
  274. key = chr(0)
  275. if event.keysym_num < 256:
  276. key = chr(event.keysym_num)
  277. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
  278. shift, key, 0, event.keysym)
  279. self._Iren.KeyReleaseEvent()
  280. def ConfigureEvent(self, event):
  281. self._Iren.SetSize(event.width, event.height)
  282. self._Iren.ConfigureEvent()
  283. def EnterEvent(self, event, ctrl, shift):
  284. if self._FocusOnEnter:
  285. self._GrabFocus()
  286. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl, shift,
  287. chr(0), 0, None)
  288. self._Iren.EnterEvent()
  289. def LeaveEvent(self, event, ctrl, shift):
  290. if self._FocusOnEnter and (self._OldFocus != None):
  291. self._OldFocus.focus()
  292. self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl, shift,
  293. chr(0), 0, None)
  294. self._Iren.LeaveEvent()
  295. def ExposeEvent(self):
  296. if (not self.__InExpose):
  297. self.__InExpose = 1
  298. if (not self._RenderWindow.IsA('vtkCocoaRenderWindow')):
  299. self.update()
  300. self._RenderWindow.Render()
  301. self.__InExpose = 0
  302. def GetRenderWindow(self):
  303. addr = self.tk.call(self._w, 'GetRenderWindow')[5:]
  304. return vtkRenderWindow('_%s_vtkRenderWindow_p' % addr)
  305. def Render(self):
  306. self._RenderWindow.Render()
  307. #----------------------------------------------------------------------------
  308. def vtkRenderWindowInteractorConeExample():
  309. """Like it says, just a simple example
  310. """
  311. from vtkmodules.vtkFiltersSources import vtkConeSource
  312. from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer
  313. # load implementations for rendering and interaction factory classes
  314. import vtkmodules.vtkRenderingOpenGL2
  315. import vtkmodules.vtkInteractionStyle
  316. # create root window
  317. root = tkinter.Tk()
  318. # create vtkTkRenderWidget
  319. pane = vtkTkRenderWindowInteractor(root, width=300, height=300)
  320. pane.Initialize()
  321. def quit(obj=root):
  322. obj.quit()
  323. pane.AddObserver("ExitEvent", lambda o,e,q=quit: q())
  324. ren = vtkRenderer()
  325. pane.GetRenderWindow().AddRenderer(ren)
  326. cone = vtkConeSource()
  327. cone.SetResolution(8)
  328. coneMapper = vtkPolyDataMapper()
  329. coneMapper.SetInputConnection(cone.GetOutputPort())
  330. coneActor = vtkActor()
  331. coneActor.SetMapper(coneMapper)
  332. ren.AddActor(coneActor)
  333. # pack the pane into the tk root
  334. pane.pack(fill='both', expand=1)
  335. pane.Start()
  336. # start the tk mainloop
  337. root.mainloop()
  338. if __name__ == "__main__":
  339. vtkRenderWindowInteractorConeExample()