init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
"""Tkinter widgets for VTK."""
|
||||
|
||||
__all__ = ['vtkTkRenderWidget', 'vtkTkImageViewerWidget',
|
||||
'vtkTkRenderWindowInteractor', 'vtkTkPhotoImage']
|
||||
@@ -0,0 +1,101 @@
|
||||
import sys, os
|
||||
import vtkmodules
|
||||
from vtkmodules.vtkCommonCore import vtkVersion
|
||||
|
||||
def vtkLoadPythonTkWidgets(interp):
|
||||
"""vtkLoadPythonTkWidgets(interp) -- load vtk-tk widget extensions
|
||||
|
||||
This is a mess of mixed python and tcl code that searches for the
|
||||
shared object file that contains the python-vtk-tk widgets. Both
|
||||
the python path and the tcl path are searched.
|
||||
"""
|
||||
modname = 'vtkRenderingTk'
|
||||
VTK_VERSIONED_INSTALL = "ON"
|
||||
VTK_CUSTOM_LIBRARY_VERSION = "9.5"
|
||||
if VTK_VERSIONED_INSTALL in ("0", "OFF", "NO", "FALSE", "N"):
|
||||
name = modname
|
||||
elif VTK_CUSTOM_LIBRARY_VERSION:
|
||||
name = '%s-%s' % (modname,VTK_CUSTOM_LIBRARY_VERSION)
|
||||
else:
|
||||
X = vtkVersion.GetVTKMajorVersion()
|
||||
Y = vtkVersion.GetVTKMinorVersion()
|
||||
name = '%s-%d.%d' % (modname,X,Y)
|
||||
pkgname = modname.lower().capitalize()
|
||||
|
||||
# find out if the module is already loaded
|
||||
loadedpkgs = interp.call('info', 'loaded')
|
||||
found = False
|
||||
try:
|
||||
# check for result returned as a string
|
||||
found = (loadedpkgs.find(pkgname) >= 0)
|
||||
except AttributeError:
|
||||
# check for result returned as nested tuples
|
||||
for pkgtuple in loadedpkgs:
|
||||
found |= (pkgname in pkgtuple)
|
||||
if found:
|
||||
return
|
||||
|
||||
# create the platform-dependent file name
|
||||
prefix = ''
|
||||
if sys.platform == 'cygwin':
|
||||
prefix = 'cyg'
|
||||
elif os.name == 'posix':
|
||||
prefix = 'lib'
|
||||
extension = interp.call('info', 'sharedlibextension')
|
||||
filename = prefix+name+extension
|
||||
|
||||
# create an list of paths to search
|
||||
vtkmodules_dir = os.path.dirname(vtkmodules.__file__)
|
||||
pathlist = [vtkmodules_dir]
|
||||
|
||||
# a likely relative path for linux
|
||||
if sys.platform == 'linux':
|
||||
package_dir = os.path.dirname(vtkmodules_dir)
|
||||
python_dir = os.path.dirname(package_dir)
|
||||
if os.path.basename(python_dir).startswith('python'):
|
||||
lib_dir = os.path.dirname(python_dir)
|
||||
if os.path.basename(lib_dir).startswith('lib'):
|
||||
pathlist.append(lib_dir)
|
||||
|
||||
# add tcl paths, ensure that {} is handled properly
|
||||
try:
|
||||
auto_paths = interp.getvar('auto_path').split()
|
||||
except AttributeError:
|
||||
auto_paths = interp.getvar('auto_path')
|
||||
for path in auto_paths:
|
||||
prev = str(pathlist[-1])
|
||||
try:
|
||||
# try block needed when one uses Gordon McMillan's Python
|
||||
# Installer.
|
||||
if len(prev) > 0 and prev[0] == '{' and prev[-1] != '}':
|
||||
pathlist[-1] = prev+' '+path
|
||||
else:
|
||||
pathlist.append(path)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# a common installation path
|
||||
if os.name == 'posix':
|
||||
pathlist.append('/usr/local/lib')
|
||||
|
||||
# attempt to load
|
||||
for path in pathlist:
|
||||
try:
|
||||
# If the path object is not str, it means that it is a
|
||||
# Tkinter path object.
|
||||
if not isinstance(path, str):
|
||||
path = path.string
|
||||
# try block needed when one uses Gordon McMillan's Python
|
||||
# Installer.
|
||||
if len(path) > 0 and path[0] == '{' and path[-1] == '}':
|
||||
path = path[1:-1]
|
||||
fullpath = os.path.join(path, filename)
|
||||
except AttributeError:
|
||||
pass
|
||||
if ' ' in fullpath:
|
||||
fullpath = '{'+fullpath+'}'
|
||||
if interp.eval('catch {load '+fullpath+' '+pkgname+'}') == '0':
|
||||
return
|
||||
|
||||
# re-generate the error
|
||||
interp.call('load', filename, pkgname)
|
||||
@@ -0,0 +1,366 @@
|
||||
"""
|
||||
A vtkTkImageViewerWidget for python, which is based on the
|
||||
vtkTkImageWindowWidget.
|
||||
|
||||
Specify double=1 to get a double-buffered window.
|
||||
|
||||
Created by David Gobbi, Nov 1999
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import math, os, sys
|
||||
from vtkmodules.vtkCommonExecutionModel import vtkStreamingDemandDrivenPipeline
|
||||
from vtkmodules.vtkInteractionImage import vtkImageViewer
|
||||
from vtkmodules.vtkRenderingCore import vtkActor2D, vtkTextMapper
|
||||
|
||||
import tkinter
|
||||
|
||||
from .vtkLoadPythonTkWidgets import vtkLoadPythonTkWidgets
|
||||
|
||||
class vtkTkImageViewerWidget(tkinter.Widget):
|
||||
"""
|
||||
A vtkTkImageViewerWidget for Python.
|
||||
|
||||
Use GetImageViewer() to get the vtkImageViewer.
|
||||
|
||||
Create with the keyword double=1 in order to generate a
|
||||
double-buffered viewer.
|
||||
|
||||
Create with the keyword focus_on_enter=1 to enable
|
||||
focus-follows-mouse. The default is for a click-to-focus mode.
|
||||
"""
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
iv -- Use passed image viewer instead of creating a new one.
|
||||
|
||||
double -- If True, generate a double-buffered viewer.
|
||||
Defaults to False.
|
||||
|
||||
focus_on_enter -- If True, use a focus-follows-mouse mode.
|
||||
Defaults to False where the widget will use a click-to-focus
|
||||
mode.
|
||||
"""
|
||||
# load the necessary extensions into tk
|
||||
vtkLoadPythonTkWidgets(master.tk)
|
||||
|
||||
try: # use specified vtkImageViewer
|
||||
imageViewer = kw['iv']
|
||||
except KeyError: # or create one if none specified
|
||||
imageViewer = vtkImageViewer()
|
||||
|
||||
doubleBuffer = 0
|
||||
try:
|
||||
if kw['double']:
|
||||
doubleBuffer = 1
|
||||
del kw['double']
|
||||
except:
|
||||
pass
|
||||
|
||||
# check if focus should follow mouse
|
||||
if kw.get('focus_on_enter'):
|
||||
self._FocusOnEnter = 1
|
||||
del kw['focus_on_enter']
|
||||
else:
|
||||
self._FocusOnEnter = 0
|
||||
|
||||
kw['iv'] = imageViewer.GetAddressAsString("vtkImageViewer")
|
||||
tkinter.Widget.__init__(self, master, 'vtkTkImageViewerWidget',
|
||||
cnf, kw)
|
||||
if doubleBuffer:
|
||||
imageViewer.GetRenderWindow().DoubleBufferOn()
|
||||
|
||||
self.BindTkImageViewer()
|
||||
|
||||
def __getattr__(self,attr):
|
||||
# because the tk part of vtkTkImageViewerWidget must have
|
||||
# the only remaining reference to the ImageViewer when
|
||||
# it is destroyed, we can't actually store the ImageViewer
|
||||
# as an attribute but instead have to get it from the tk-side
|
||||
if attr == '_ImageViewer':
|
||||
addr = self.tk.call(self._w, 'GetImageViewer')[5:]
|
||||
return vtkImageViewer('_%s_vtkImageViewer_p' % addr)
|
||||
raise AttributeError(self.__class__.__name__ +
|
||||
" has no attribute named " + attr)
|
||||
|
||||
def GetImageViewer(self):
|
||||
return self._ImageViewer
|
||||
|
||||
def Render(self):
|
||||
self._ImageViewer.Render()
|
||||
|
||||
def BindTkImageViewer(self):
|
||||
imager = self._ImageViewer.GetRenderer()
|
||||
|
||||
# stuff for window level text.
|
||||
mapper = vtkTextMapper()
|
||||
mapper.SetInput("none")
|
||||
t_prop = mapper.GetTextProperty()
|
||||
t_prop.SetFontFamilyToTimes()
|
||||
t_prop.SetFontSize(18)
|
||||
t_prop.BoldOn()
|
||||
t_prop.ShadowOn()
|
||||
|
||||
self._LevelMapper = mapper
|
||||
|
||||
actor = vtkActor2D()
|
||||
actor.SetMapper(mapper)
|
||||
actor.SetLayerNumber(1)
|
||||
actor.GetPositionCoordinate().SetValue(4,22)
|
||||
actor.GetProperty().SetColor(1,1,0.5)
|
||||
actor.SetVisibility(0)
|
||||
imager.AddViewProp(actor)
|
||||
|
||||
self._LevelActor = actor
|
||||
|
||||
mapper = vtkTextMapper()
|
||||
mapper.SetInput("none")
|
||||
t_prop = mapper.GetTextProperty()
|
||||
t_prop.SetFontFamilyToTimes()
|
||||
t_prop.SetFontSize(18)
|
||||
t_prop.BoldOn()
|
||||
t_prop.ShadowOn()
|
||||
|
||||
self._WindowMapper = mapper
|
||||
|
||||
actor = vtkActor2D()
|
||||
actor.SetMapper(mapper)
|
||||
actor.SetLayerNumber(1)
|
||||
actor.GetPositionCoordinate().SetValue(4,4)
|
||||
actor.GetProperty().SetColor(1,1,0.5)
|
||||
actor.SetVisibility(0)
|
||||
imager.AddViewProp(actor)
|
||||
|
||||
self._WindowActor = actor
|
||||
|
||||
self._LastX = 0
|
||||
self._LastY = 0
|
||||
self._OldFocus = 0
|
||||
self._InExpose = 0
|
||||
|
||||
# bindings
|
||||
# window level
|
||||
self.bind("<ButtonPress-1>",
|
||||
lambda e,s=self: s.StartWindowLevelInteraction(e.x,e.y))
|
||||
self.bind("<B1-Motion>",
|
||||
lambda e,s=self: s.UpdateWindowLevelInteraction(e.x,e.y))
|
||||
self.bind("<ButtonRelease-1>",
|
||||
lambda e,s=self: s.EndWindowLevelInteraction())
|
||||
|
||||
# Get the value
|
||||
self.bind("<ButtonPress-3>",
|
||||
lambda e,s=self: s.StartQueryInteraction(e.x,e.y))
|
||||
self.bind("<B3-Motion>",
|
||||
lambda e,s=self: s.UpdateQueryInteraction(e.x,e.y))
|
||||
self.bind("<ButtonRelease-3>",
|
||||
lambda e,s=self: s.EndQueryInteraction())
|
||||
|
||||
self.bind("<Expose>",
|
||||
lambda e,s=self: s.ExposeTkImageViewer())
|
||||
self.bind("<Enter>",
|
||||
lambda e,s=self: s.EnterTkViewer())
|
||||
self.bind("<Leave>",
|
||||
lambda e,s=self: s.LeaveTkViewer())
|
||||
self.bind("<KeyPress-e>",
|
||||
lambda e,s=self: s.quit())
|
||||
self.bind("<KeyPress-r>",
|
||||
lambda e,s=self: s.ResetTkImageViewer())
|
||||
|
||||
def _GrabFocus(self):
|
||||
self._OldFocus=self.focus_get()
|
||||
self.focus()
|
||||
|
||||
def EnterTkViewer(self):
|
||||
if self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
|
||||
def LeaveTkViewer(self):
|
||||
if self._FocusOnEnter and (self._OldFocus != None):
|
||||
self._OldFocus.focus()
|
||||
|
||||
def ExposeTkImageViewer(self):
|
||||
if (self._InExpose == 0):
|
||||
self._InExpose = 1
|
||||
if (not self._ImageViewer.GetRenderWindow().
|
||||
IsA('vtkCocoaRenderWindow')):
|
||||
self.update()
|
||||
self._ImageViewer.Render()
|
||||
self._InExpose = 0
|
||||
|
||||
def StartWindowLevelInteraction(self,x,y):
|
||||
if not self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
viewer = self._ImageViewer
|
||||
self._LastX = x
|
||||
self._LastY = y
|
||||
self._Window = float(viewer.GetColorWindow())
|
||||
self._Level = float(viewer.GetColorLevel())
|
||||
|
||||
# make the window level text visible
|
||||
self._LevelActor.SetVisibility(1)
|
||||
self._WindowActor.SetVisibility(1)
|
||||
|
||||
self.UpdateWindowLevelInteraction(x,y)
|
||||
|
||||
def EndWindowLevelInteraction(self):
|
||||
# make the window level text invisible
|
||||
self._LevelActor.SetVisibility(0)
|
||||
self._WindowActor.SetVisibility(0)
|
||||
self.Render()
|
||||
|
||||
def UpdateWindowLevelInteraction(self,x,y):
|
||||
# compute normalized delta
|
||||
dx = 4.0*(x - self._LastX)/self.winfo_width()*self._Window
|
||||
dy = 4.0*(self._LastY - y)/self.winfo_height()*self._Level
|
||||
|
||||
# abs so that direction does not flip
|
||||
if (self._Window < 0.0):
|
||||
dx = -dx
|
||||
if (self._Level < 0.0):
|
||||
dy = -dy
|
||||
|
||||
# compute new window level
|
||||
window = self._Window + dx
|
||||
if (window < 0.0):
|
||||
level = self._Level + dy
|
||||
else:
|
||||
level = self._Level - dy
|
||||
|
||||
viewer = self._ImageViewer
|
||||
viewer.SetColorWindow(window)
|
||||
viewer.SetColorLevel(level)
|
||||
|
||||
self._WindowMapper.SetInput("Window: %g" % window)
|
||||
self._LevelMapper.SetInput("Level: %g" % level)
|
||||
|
||||
self.Render()
|
||||
|
||||
|
||||
def ResetTkImageViewer(self):
|
||||
# Reset: Set window level to show all values
|
||||
viewer = self._ImageViewer
|
||||
input = viewer.GetInput()
|
||||
if (input == None):
|
||||
return
|
||||
|
||||
# Get the extent in viewer
|
||||
z = viewer.GetZSlice()
|
||||
|
||||
input.UpdateInformation()
|
||||
info = input.GetOutputInformation(0)
|
||||
ext = info.Get(vtkStreamingDemandDrivenPipeline.WHOLE_EXTENT())
|
||||
ext[4] = z
|
||||
ext[5] = z
|
||||
input.Update(0, 1, 0, ext)
|
||||
|
||||
(low,high) = input.GetScalarRange()
|
||||
|
||||
viewer.SetColorWindow(high - low)
|
||||
viewer.SetColorLevel((high + low) * 0.5)
|
||||
|
||||
self.Render()
|
||||
|
||||
def StartQueryInteraction(self,x,y):
|
||||
if not self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
# Query PixleValue stuff
|
||||
self._WindowActor.SetVisibility(1)
|
||||
self.UpdateQueryInteraction(x,y)
|
||||
|
||||
def EndQueryInteraction(self):
|
||||
self._WindowActor.SetVisibility(0)
|
||||
self.Render()
|
||||
|
||||
def UpdateQueryInteraction(self,x,y):
|
||||
viewer = self._ImageViewer
|
||||
input = viewer.GetInput()
|
||||
z = viewer.GetZSlice()
|
||||
|
||||
# y is flipped upside down
|
||||
y = self.winfo_height() - y
|
||||
|
||||
# make sure point is in the extent of the image.
|
||||
(xMin,xMax,yMin,yMax,zMin,zMax) = input.GetExtent()
|
||||
if (x < xMin or x > xMax or y < yMin or \
|
||||
y > yMax or z < zMin or z > zMax):
|
||||
return
|
||||
|
||||
numComps = input.GetNumberOfScalarComponents()
|
||||
text = ""
|
||||
for i in xrange(numComps):
|
||||
val = input.GetScalarComponentAsDouble(x,y,z,i)
|
||||
text = "%s %.1f" % (text,val)
|
||||
|
||||
self._WindowMapper.SetInput("(%d, %d): %s" % (x,y,text))
|
||||
|
||||
self.Render()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# an example of how to use this widget
|
||||
if __name__ == "__main__":
|
||||
from vtkmodules.vtkImagingSources import vtkImageCanvasSource2D
|
||||
# load implementations for rendering and interaction factory classes
|
||||
import vtkmodules.vtkRenderingOpenGL2
|
||||
import vtkmodules.vtkInteractionStyle
|
||||
|
||||
canvas = vtkImageCanvasSource2D()
|
||||
canvas.SetNumberOfScalarComponents(3)
|
||||
canvas.SetScalarType(3)
|
||||
canvas.SetExtent(0,511,0,511,0,0)
|
||||
canvas.SetDrawColor(100,100,0)
|
||||
canvas.FillBox(0,511,0,511)
|
||||
canvas.SetDrawColor(200,0,200)
|
||||
canvas.FillBox(32,511,100,500)
|
||||
canvas.SetDrawColor(100,0,0)
|
||||
canvas.FillTube(550,20,30,400,5)
|
||||
canvas.SetDrawColor(255,255,255)
|
||||
canvas.DrawSegment3D(10,20,0,90,510,0)
|
||||
canvas.SetDrawColor(200,50,50)
|
||||
canvas.DrawSegment3D(510,90,0,10,20,0)
|
||||
|
||||
# Check segment clipping
|
||||
canvas.SetDrawColor(0,200,0)
|
||||
canvas.DrawSegment(-10,30,30,-10)
|
||||
canvas.DrawSegment(-10,481,30,521)
|
||||
canvas.DrawSegment(481,-10,521,30)
|
||||
canvas.DrawSegment(481,521,521,481)
|
||||
|
||||
# Check Filling a triangle
|
||||
canvas.SetDrawColor(20,200,200)
|
||||
canvas.FillTriangle(-100,100,190,150,40,300)
|
||||
|
||||
# Check drawing a circle
|
||||
canvas.SetDrawColor(250,250,10)
|
||||
canvas.DrawCircle(350,350,200.0)
|
||||
|
||||
# Check drawing a point
|
||||
canvas.SetDrawColor(250,250,250)
|
||||
canvas.DrawPoint(350,350)
|
||||
canvas.DrawPoint(350,550)
|
||||
|
||||
# Test filling functionality
|
||||
canvas.SetDrawColor(55,0,0)
|
||||
canvas.DrawCircle(450,350,80.0)
|
||||
canvas.SetDrawColor(100,255,100)
|
||||
canvas.FillPixel(450,350)
|
||||
|
||||
# Create the GUI: two renderer widgets and a quit button
|
||||
|
||||
frame = tkinter.Frame()
|
||||
|
||||
widget = vtkTkImageViewerWidget(frame,width=512,height=512,double=1)
|
||||
viewer = widget.GetImageViewer()
|
||||
viewer.SetInputConnection(canvas.GetOutputPort())
|
||||
viewer.SetColorWindow(256)
|
||||
viewer.SetColorLevel(127.5)
|
||||
|
||||
button = tkinter.Button(frame,text="Quit",command=frame.quit)
|
||||
|
||||
widget.pack(side='top',padx=3,pady=3,fill='both',expand='t')
|
||||
frame.pack(fill='both',expand='t')
|
||||
button.pack(fill='x')
|
||||
|
||||
frame.mainloop()
|
||||
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
A subclass of tkinter.PhotoImage that connects a
|
||||
vtkImageData to a photo widget.
|
||||
|
||||
Created by Daniel Blezek, August 2002
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import sys
|
||||
|
||||
import tkinter
|
||||
|
||||
from .vtkLoadPythonTkWidgets import vtkLoadPythonTkWidgets
|
||||
|
||||
class vtkTkPhotoImage ( tkinter.PhotoImage ):
|
||||
"""
|
||||
A subclass of PhotoImage with helper functions
|
||||
for displaying vtkImageData
|
||||
"""
|
||||
def __init__ ( self, **kw ):
|
||||
# Caller the superclass
|
||||
tkinter.PhotoImage.__init__ ( self, kw )
|
||||
vtkLoadPythonTkWidgets ( self.tk )
|
||||
|
||||
def PutImageSlice ( self, image, z, orientation='transverse', window=256, level=128 ):
|
||||
t = str ( image.__this__ )
|
||||
s = 'vtkImageDataToTkPhoto %s %s %d %s %d %d' % ( t, self.name, z, orientation, window, level )
|
||||
self.tk.eval ( s )
|
||||
@@ -0,0 +1,474 @@
|
||||
"""
|
||||
A simple vtkTkRenderWidget for tkinter.
|
||||
|
||||
Created by David Gobbi, April 1999
|
||||
|
||||
May ??, 1999 - Modifications performed by Heather Drury,
|
||||
to rewrite _pan to match method in TkInteractor.tcl
|
||||
May 11, 1999 - Major rewrite by David Gobbi to make the
|
||||
interactor bindings identical to the TkInteractor.tcl
|
||||
bindings.
|
||||
July 14, 1999 - Added modification by Ken Martin for VTK 2.4, to
|
||||
use vtk widgets instead of Togl.
|
||||
Aug 29, 1999 - Renamed file to vtkRenderWidget.py
|
||||
Nov 14, 1999 - Added support for keyword 'rw'
|
||||
Mar 23, 2000 - Extensive but backwards compatible changes,
|
||||
improved documentation
|
||||
|
||||
A few important notes:
|
||||
|
||||
This class is meant to be used as a base-class widget for
|
||||
doing VTK rendering in Python.
|
||||
|
||||
In VTK (and C++) there is a very important distinction between
|
||||
public ivars (attributes in pythonspeak), protected ivars, and
|
||||
private ivars. When you write a python class that you want
|
||||
to 'look and feel' like a VTK class, you should follow these rules.
|
||||
|
||||
1) Attributes should never be public. Attributes should always be
|
||||
either protected (prefixed with a single underscore) or private
|
||||
(prefixed with a double underscore). You can provide access to
|
||||
attributes through public Set/Get methods (same as VTK).
|
||||
|
||||
2) Use a single underscore to denote a protected attribute, e.g.
|
||||
self._RenderWindow is protected (can be accessed from this
|
||||
class or a derived class).
|
||||
|
||||
3) Use a double underscore to denote a private attribute, e.g.
|
||||
self.__InExpose cannot be accessed outside of this class.
|
||||
|
||||
All attributes should be 'declared' in the __init__() function
|
||||
i.e. set to some initial value. Don't forget that 'None' means
|
||||
'NULL' - the python/vtk wrappers guarantee their equivalence.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import math, os, sys
|
||||
from vtkmodules.vtkRenderingCore import vtkCellPicker, vtkProperty, vtkRenderWindow
|
||||
|
||||
import tkinter
|
||||
|
||||
from .vtkLoadPythonTkWidgets import vtkLoadPythonTkWidgets
|
||||
|
||||
class vtkTkRenderWidget(tkinter.Widget):
|
||||
"""
|
||||
A vtkTkRenderWidget for Python.
|
||||
|
||||
Use GetRenderWindow() to get the vtkRenderWindow.
|
||||
|
||||
Create with the keyword stereo=1 in order to generate a
|
||||
stereo-capable window.
|
||||
|
||||
Create with the keyword focus_on_enter=1 to enable
|
||||
focus-follows-mouse. The default is for a click-to-focus mode.
|
||||
"""
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
rw -- Use passed render window instead of creating a new one.
|
||||
|
||||
stereo -- If True, generate a stereo-capable window.
|
||||
Defaults to False.
|
||||
|
||||
focus_on_enter -- If True, use a focus-follows-mouse mode.
|
||||
Defaults to False where the widget will use a click-to-focus
|
||||
mode.
|
||||
"""
|
||||
# load the necessary extensions into tk
|
||||
vtkLoadPythonTkWidgets(master.tk)
|
||||
|
||||
try: # check to see if a render window was specified
|
||||
renderWindow = kw['rw']
|
||||
except KeyError:
|
||||
renderWindow = vtkRenderWindow()
|
||||
|
||||
try: # was a stereo rendering context requested?
|
||||
if kw['stereo']:
|
||||
renderWindow.StereoCapableWindowOn()
|
||||
del kw['stereo']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# check if focus should follow mouse
|
||||
if kw.get('focus_on_enter'):
|
||||
self._FocusOnEnter = 1
|
||||
del kw['focus_on_enter']
|
||||
else:
|
||||
self._FocusOnEnter = 0
|
||||
|
||||
kw['rw'] = renderWindow.GetAddressAsString("vtkRenderWindow")
|
||||
tkinter.Widget.__init__(self, master, 'vtkTkRenderWidget', cnf, kw)
|
||||
|
||||
self._CurrentRenderer = None
|
||||
self._CurrentCamera = None
|
||||
self._CurrentZoom = 1.0
|
||||
self._CurrentLight = None
|
||||
|
||||
self._ViewportCenterX = 0
|
||||
self._ViewportCenterY = 0
|
||||
|
||||
self._Picker = vtkCellPicker()
|
||||
self._PickedAssembly = None
|
||||
self._PickedProperty = vtkProperty()
|
||||
self._PickedProperty.SetColor(1,0,0)
|
||||
self._PrePickedProperty = None
|
||||
|
||||
self._OldFocus = None
|
||||
|
||||
# used by the LOD actors
|
||||
self._DesiredUpdateRate = 15
|
||||
self._StillUpdateRate = 0.0001
|
||||
|
||||
# these record the previous mouse position
|
||||
self._LastX = 0
|
||||
self._LastY = 0
|
||||
|
||||
# private attributes
|
||||
self.__InExpose = 0
|
||||
|
||||
# create the Tk bindings
|
||||
self.BindTkRenderWidget()
|
||||
|
||||
def __getattr__(self,attr):
|
||||
# because the tk part of vtkTkRenderWidget must have
|
||||
# the only remaining reference to the RenderWindow when
|
||||
# it is destroyed, we can't actually store the RenderWindow
|
||||
# as an attribute but instead have to get it from the tk-side
|
||||
if attr == '_RenderWindow':
|
||||
return self.GetRenderWindow()
|
||||
raise AttributeError(self.__class__.__name__ +
|
||||
" has no attribute named " + attr)
|
||||
|
||||
def BindTkRenderWidget(self):
|
||||
"""
|
||||
Bind some default actions.
|
||||
"""
|
||||
self.bind("<ButtonPress>",
|
||||
lambda e,s=self: s.StartMotion(e.x,e.y))
|
||||
self.bind("<ButtonRelease>",
|
||||
lambda e,s=self: s.EndMotion(e.x,e.y))
|
||||
self.bind("<B1-Motion>",
|
||||
lambda e,s=self: s.Rotate(e.x,e.y))
|
||||
self.bind("<B2-Motion>",
|
||||
lambda e,s=self: s.Pan(e.x,e.y))
|
||||
self.bind("<B3-Motion>",
|
||||
lambda e,s=self: s.Zoom(e.x,e.y))
|
||||
self.bind("<Shift-B1-Motion>",
|
||||
lambda e,s=self: s.Pan(e.x,e.y))
|
||||
self.bind("<KeyPress-r>",
|
||||
lambda e,s=self: s.Reset(e.x,e.y))
|
||||
self.bind("<KeyPress-u>",
|
||||
lambda e,s=self: s.deiconify())
|
||||
self.bind("<KeyPress-w>",
|
||||
lambda e,s=self: s.Wireframe())
|
||||
self.bind("<KeyPress-s>",
|
||||
lambda e,s=self: s.Surface())
|
||||
self.bind("<KeyPress-p>",
|
||||
lambda e,s=self: s.PickActor(e.x,e.y))
|
||||
if self._FocusOnEnter:
|
||||
self.bind("<Enter>",
|
||||
lambda e,s=self: s.Enter(e.x,e.y))
|
||||
self.bind("<Leave>",
|
||||
lambda e,s=self: s.Leave(e.x,e.y))
|
||||
else:
|
||||
self.bind("<ButtonPress>",
|
||||
lambda e,s=self: s.Enter(e.x,e.y))
|
||||
self.bind("<Expose>",
|
||||
lambda e,s=self: s.Expose())
|
||||
|
||||
def GetZoomFactor(self):
|
||||
return self._CurrentZoom
|
||||
|
||||
def SetDesiredUpdateRate(self, rate):
|
||||
"""Mirrors the method with the same name in
|
||||
vtkRenderWindowInteractor."""
|
||||
self._DesiredUpdateRate = rate
|
||||
|
||||
def GetDesiredUpdateRate(self):
|
||||
"""Mirrors the method with the same name in
|
||||
vtkRenderWindowInteractor."""
|
||||
return self._DesiredUpdateRate
|
||||
|
||||
def SetStillUpdateRate(self, rate):
|
||||
"""Mirrors the method with the same name in
|
||||
vtkRenderWindowInteractor."""
|
||||
self._StillUpdateRate = rate
|
||||
|
||||
def GetStillUpdateRate(self):
|
||||
"""Mirrors the method with the same name in
|
||||
vtkRenderWindowInteractor."""
|
||||
return self._StillUpdateRate
|
||||
|
||||
def GetRenderWindow(self):
|
||||
addr = self.tk.call(self._w, 'GetRenderWindow')[5:]
|
||||
return vtkRenderWindow('_%s_vtkRenderWindow_p' % addr)
|
||||
|
||||
def GetPicker(self):
|
||||
return self._Picker
|
||||
|
||||
def Expose(self):
|
||||
if (not self.__InExpose):
|
||||
self.__InExpose = 1
|
||||
if (not self._RenderWindow.IsA('vtkCocoaRenderWindow')):
|
||||
self.update()
|
||||
self._RenderWindow.Render()
|
||||
self.__InExpose = 0
|
||||
|
||||
def Render(self):
|
||||
if (self._CurrentLight):
|
||||
light = self._CurrentLight
|
||||
light.SetPosition(self._CurrentCamera.GetPosition())
|
||||
light.SetFocalPoint(self._CurrentCamera.GetFocalPoint())
|
||||
|
||||
self._RenderWindow.Render()
|
||||
|
||||
def UpdateRenderer(self,x,y):
|
||||
"""
|
||||
UpdateRenderer will identify the renderer under the mouse and set
|
||||
up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
|
||||
"""
|
||||
windowX = self.winfo_width()
|
||||
windowY = self.winfo_height()
|
||||
|
||||
renderers = self._RenderWindow.GetRenderers()
|
||||
numRenderers = renderers.GetNumberOfItems()
|
||||
|
||||
self._CurrentRenderer = None
|
||||
renderers.InitTraversal()
|
||||
for i in range(0,numRenderers):
|
||||
renderer = renderers.GetNextItem()
|
||||
vx,vy = (0,0)
|
||||
if (windowX > 1):
|
||||
vx = float(x)/(windowX-1)
|
||||
if (windowY > 1):
|
||||
vy = (windowY-float(y)-1)/(windowY-1)
|
||||
(vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()
|
||||
|
||||
if (vx >= vpxmin and vx <= vpxmax and
|
||||
vy >= vpymin and vy <= vpymax):
|
||||
self._CurrentRenderer = renderer
|
||||
self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
|
||||
+vpxmin
|
||||
self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
|
||||
+vpymin
|
||||
self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
|
||||
lights = self._CurrentRenderer.GetLights()
|
||||
lights.InitTraversal()
|
||||
self._CurrentLight = lights.GetNextItem()
|
||||
break
|
||||
|
||||
self._LastX = x
|
||||
self._LastY = y
|
||||
|
||||
def GetCurrentRenderer(self):
|
||||
return self._CurrentRenderer
|
||||
|
||||
def Enter(self,x,y):
|
||||
self._OldFocus=self.focus_get()
|
||||
self.focus()
|
||||
self.StartMotion(x, y)
|
||||
|
||||
def Leave(self,x,y):
|
||||
if (self._OldFocus != None):
|
||||
self._OldFocus.focus()
|
||||
|
||||
def StartMotion(self,x,y):
|
||||
self.GetRenderWindow().SetDesiredUpdateRate(self._DesiredUpdateRate)
|
||||
self.UpdateRenderer(x,y)
|
||||
|
||||
def EndMotion(self,x,y):
|
||||
self.GetRenderWindow().SetDesiredUpdateRate(self._StillUpdateRate)
|
||||
if self._CurrentRenderer:
|
||||
self.Render()
|
||||
|
||||
def Rotate(self,x,y):
|
||||
if self._CurrentRenderer:
|
||||
|
||||
self._CurrentCamera.Azimuth(self._LastX - x)
|
||||
self._CurrentCamera.Elevation(y - self._LastY)
|
||||
self._CurrentCamera.OrthogonalizeViewUp()
|
||||
|
||||
self._LastX = x
|
||||
self._LastY = y
|
||||
|
||||
self._CurrentRenderer.ResetCameraClippingRange()
|
||||
self.Render()
|
||||
|
||||
def Pan(self,x,y):
|
||||
if self._CurrentRenderer:
|
||||
|
||||
renderer = self._CurrentRenderer
|
||||
camera = self._CurrentCamera
|
||||
(pPoint0,pPoint1,pPoint2) = camera.GetPosition()
|
||||
(fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
|
||||
|
||||
if (camera.GetParallelProjection()):
|
||||
renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
|
||||
renderer.WorldToDisplay()
|
||||
fx,fy,fz = renderer.GetDisplayPoint()
|
||||
renderer.SetDisplayPoint(fx-x+self._LastX,
|
||||
fy+y-self._LastY,
|
||||
fz)
|
||||
renderer.DisplayToWorld()
|
||||
fx,fy,fz,fw = renderer.GetWorldPoint()
|
||||
camera.SetFocalPoint(fx,fy,fz)
|
||||
|
||||
renderer.SetWorldPoint(pPoint0,pPoint1,pPoint2,1.0)
|
||||
renderer.WorldToDisplay()
|
||||
fx,fy,fz = renderer.GetDisplayPoint()
|
||||
renderer.SetDisplayPoint(fx-x+self._LastX,
|
||||
fy+y-self._LastY,
|
||||
fz)
|
||||
renderer.DisplayToWorld()
|
||||
fx,fy,fz,fw = renderer.GetWorldPoint()
|
||||
camera.SetPosition(fx,fy,fz)
|
||||
|
||||
else:
|
||||
(fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
|
||||
# Specify a point location in world coordinates
|
||||
renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
|
||||
renderer.WorldToDisplay()
|
||||
# Convert world point coordinates to display coordinates
|
||||
dPoint = renderer.GetDisplayPoint()
|
||||
focalDepth = dPoint[2]
|
||||
|
||||
aPoint0 = self._ViewportCenterX + (x - self._LastX)
|
||||
aPoint1 = self._ViewportCenterY - (y - self._LastY)
|
||||
|
||||
renderer.SetDisplayPoint(aPoint0,aPoint1,focalDepth)
|
||||
renderer.DisplayToWorld()
|
||||
|
||||
(rPoint0,rPoint1,rPoint2,rPoint3) = renderer.GetWorldPoint()
|
||||
if (rPoint3 != 0.0):
|
||||
rPoint0 = rPoint0/rPoint3
|
||||
rPoint1 = rPoint1/rPoint3
|
||||
rPoint2 = rPoint2/rPoint3
|
||||
|
||||
camera.SetFocalPoint((fPoint0 - rPoint0) + fPoint0,
|
||||
(fPoint1 - rPoint1) + fPoint1,
|
||||
(fPoint2 - rPoint2) + fPoint2)
|
||||
|
||||
camera.SetPosition((fPoint0 - rPoint0) + pPoint0,
|
||||
(fPoint1 - rPoint1) + pPoint1,
|
||||
(fPoint2 - rPoint2) + pPoint2)
|
||||
|
||||
self._LastX = x
|
||||
self._LastY = y
|
||||
|
||||
self.Render()
|
||||
|
||||
def Zoom(self,x,y):
|
||||
if self._CurrentRenderer:
|
||||
|
||||
renderer = self._CurrentRenderer
|
||||
camera = self._CurrentCamera
|
||||
|
||||
zoomFactor = math.pow(1.02,(0.5*(self._LastY - y)))
|
||||
self._CurrentZoom = self._CurrentZoom * zoomFactor
|
||||
|
||||
if camera.GetParallelProjection():
|
||||
parallelScale = camera.GetParallelScale()/zoomFactor
|
||||
camera.SetParallelScale(parallelScale)
|
||||
else:
|
||||
camera.Dolly(zoomFactor)
|
||||
renderer.ResetCameraClippingRange()
|
||||
|
||||
self._LastX = x
|
||||
self._LastY = y
|
||||
|
||||
self.Render()
|
||||
|
||||
def Reset(self,x,y):
|
||||
if self._CurrentRenderer:
|
||||
self._CurrentRenderer.ResetCamera()
|
||||
|
||||
self.Render()
|
||||
|
||||
def Wireframe(self):
|
||||
actors = self._CurrentRenderer.GetActors()
|
||||
numActors = actors.GetNumberOfItems()
|
||||
actors.InitTraversal()
|
||||
for i in range(0,numActors):
|
||||
actor = actors.GetNextItem()
|
||||
actor.GetProperty().SetRepresentationToWireframe()
|
||||
|
||||
self.Render()
|
||||
|
||||
def Surface(self):
|
||||
actors = self._CurrentRenderer.GetActors()
|
||||
numActors = actors.GetNumberOfItems()
|
||||
actors.InitTraversal()
|
||||
for i in range(0,numActors):
|
||||
actor = actors.GetNextItem()
|
||||
actor.GetProperty().SetRepresentationToSurface()
|
||||
|
||||
self.Render()
|
||||
|
||||
def PickActor(self,x,y):
|
||||
if self._CurrentRenderer:
|
||||
|
||||
renderer = self._CurrentRenderer
|
||||
picker = self._Picker
|
||||
|
||||
windowY = self.winfo_height()
|
||||
picker.Pick(x,(windowY - y - 1),0.0,renderer)
|
||||
assembly = picker.GetAssembly()
|
||||
|
||||
if (self._PickedAssembly != None and
|
||||
self._PrePickedProperty != None):
|
||||
self._PickedAssembly.SetProperty(self._PrePickedProperty)
|
||||
# release hold of the property
|
||||
self._PrePickedProperty.UnRegister(self._PrePickedProperty)
|
||||
self._PrePickedProperty = None
|
||||
|
||||
if (assembly != None):
|
||||
self._PickedAssembly = assembly
|
||||
self._PrePickedProperty = self._PickedAssembly.GetProperty()
|
||||
# hold onto the property
|
||||
self._PrePickedProperty.Register(self._PrePickedProperty)
|
||||
self._PickedAssembly.SetProperty(self._PickedProperty)
|
||||
|
||||
self.Render()
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
def vtkRenderWidgetConeExample():
|
||||
"""Like it says, just a simple example
|
||||
"""
|
||||
|
||||
from vtkmodules.vtkFiltersSources import vtkConeSource
|
||||
from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer
|
||||
# load implementations for rendering and interaction factory classes
|
||||
import vtkmodules.vtkRenderingOpenGL2
|
||||
import vtkmodules.vtkInteractionStyle
|
||||
|
||||
# create root window
|
||||
root = tkinter.Tk()
|
||||
|
||||
# create vtkTkRenderWidget
|
||||
pane = vtkTkRenderWidget(root,width=300,height=300)
|
||||
|
||||
ren = vtkRenderer()
|
||||
pane.GetRenderWindow().AddRenderer(ren)
|
||||
|
||||
cone = vtkConeSource()
|
||||
cone.SetResolution(8)
|
||||
|
||||
coneMapper = vtkPolyDataMapper()
|
||||
coneMapper.SetInputConnection(cone.GetOutputPort())
|
||||
|
||||
coneActor = vtkActor()
|
||||
coneActor.SetMapper(coneMapper)
|
||||
|
||||
ren.AddActor(coneActor)
|
||||
|
||||
# pack the pane into the tk root
|
||||
pane.pack()
|
||||
|
||||
# start the tk mainloop
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
vtkRenderWidgetConeExample()
|
||||
@@ -0,0 +1,411 @@
|
||||
"""
|
||||
|
||||
A fully functional VTK widget for tkinter that uses
|
||||
vtkGenericRenderWindowInteractor. The widget is called
|
||||
vtkTkRenderWindowInteractor. The initialization part of this code is
|
||||
similar to that of the vtkTkRenderWidget.
|
||||
|
||||
Created by Prabhu Ramachandran, April 2002
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import math, os, sys
|
||||
from vtkmodules.vtkRenderingCore import vtkRenderWindow
|
||||
from vtkmodules.vtkRenderingUI import vtkGenericRenderWindowInteractor
|
||||
|
||||
import tkinter
|
||||
|
||||
from .vtkLoadPythonTkWidgets import vtkLoadPythonTkWidgets
|
||||
|
||||
class vtkTkRenderWindowInteractor(tkinter.Widget):
|
||||
""" A vtkTkRenderWidndowInteractor for Python.
|
||||
|
||||
Use GetRenderWindow() to get the vtkRenderWindow.
|
||||
|
||||
Create with the keyword stereo=1 in order to generate a
|
||||
stereo-capable window.
|
||||
|
||||
Create with the keyword focus_on_enter=1 to enable
|
||||
focus-follows-mouse. The default is for a click-to-focus mode.
|
||||
|
||||
__getattr__ is used to make the widget also behave like a
|
||||
vtkGenericRenderWindowInteractor.
|
||||
"""
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
rw -- Use passed render window instead of creating a new one.
|
||||
|
||||
stereo -- If True, generate a stereo-capable window.
|
||||
Defaults to False.
|
||||
|
||||
focus_on_enter -- If True, use a focus-follows-mouse mode.
|
||||
Defaults to False where the widget will use a click-to-focus
|
||||
mode.
|
||||
"""
|
||||
# load the necessary extensions into tk
|
||||
vtkLoadPythonTkWidgets(master.tk)
|
||||
|
||||
try: # check to see if a render window was specified
|
||||
renderWindow = kw['rw']
|
||||
except KeyError:
|
||||
renderWindow = vtkRenderWindow()
|
||||
|
||||
try: # was a stereo rendering context requested?
|
||||
if kw['stereo']:
|
||||
renderWindow.StereoCapableWindowOn()
|
||||
del kw['stereo']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# check if focus should follow mouse
|
||||
if kw.get('focus_on_enter'):
|
||||
self._FocusOnEnter = 1
|
||||
del kw['focus_on_enter']
|
||||
else:
|
||||
self._FocusOnEnter = 0
|
||||
|
||||
kw['rw'] = renderWindow.GetAddressAsString("vtkRenderWindow")
|
||||
tkinter.Widget.__init__(self, master, 'vtkTkRenderWidget', cnf, kw)
|
||||
|
||||
self._Iren = vtkGenericRenderWindowInteractor()
|
||||
self._Iren.SetRenderWindow(self._RenderWindow)
|
||||
|
||||
self._Iren.AddObserver('CreateTimerEvent', self.CreateTimer)
|
||||
self._Iren.AddObserver('DestroyTimerEvent', self.DestroyTimer)
|
||||
|
||||
self._OldFocus = None
|
||||
|
||||
# private attributes
|
||||
self.__InExpose = 0
|
||||
|
||||
# create the Tk bindings
|
||||
self.BindEvents()
|
||||
#self.tk_focusFollowsMouse()
|
||||
|
||||
def __getattr__(self, attr):
|
||||
# because the tk part of vtkTkRenderWidget must have
|
||||
# the only remaining reference to the RenderWindow when
|
||||
# it is destroyed, we can't actually store the RenderWindow
|
||||
# as an attribute but instead have to get it from the tk-side
|
||||
if attr == '__vtk__':
|
||||
return lambda t=self._Iren: t
|
||||
elif attr == '_RenderWindow':
|
||||
return self.GetRenderWindow()
|
||||
elif hasattr(self._Iren, attr):
|
||||
return getattr(self._Iren, attr)
|
||||
else:
|
||||
raise AttributeError(self.__class__.__name__ +
|
||||
" has no attribute named " + attr)
|
||||
|
||||
def BindEvents(self):
|
||||
""" Bind all the events. """
|
||||
self.bind("<Motion>",
|
||||
lambda e, s=self: s.MouseMoveEvent(e, 0, 0))
|
||||
self.bind("<Control-Motion>",
|
||||
lambda e, s=self: s.MouseMoveEvent(e, 1, 0))
|
||||
self.bind("<Shift-Motion>",
|
||||
lambda e, s=self: s.MouseMoveEvent(e, 1, 1))
|
||||
self.bind("<Control-Shift-Motion>",
|
||||
lambda e, s=self: s.MouseMoveEvent(e, 0, 1))
|
||||
|
||||
# Left Button
|
||||
self.bind("<ButtonPress-1>",
|
||||
lambda e, s=self: s.LeftButtonPressEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonPress-1>",
|
||||
lambda e, s=self: s.LeftButtonPressEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonPress-1>",
|
||||
lambda e, s=self: s.LeftButtonPressEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonPress-1>",
|
||||
lambda e, s=self: s.LeftButtonPressEvent(e, 1, 1))
|
||||
self.bind("<ButtonRelease-1>",
|
||||
lambda e, s=self: s.LeftButtonReleaseEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonRelease-1>",
|
||||
lambda e, s=self: s.LeftButtonReleaseEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonRelease-1>",
|
||||
lambda e, s=self: s.LeftButtonReleaseEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonRelease-1>",
|
||||
lambda e, s=self: s.LeftButtonReleaseEvent(e, 1, 1))
|
||||
|
||||
# Middle Button
|
||||
self.bind("<ButtonPress-2>",
|
||||
lambda e, s=self: s.MiddleButtonPressEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonPress-2>",
|
||||
lambda e, s=self: s.MiddleButtonPressEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonPress-2>",
|
||||
lambda e, s=self: s.MiddleButtonPressEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonPress-2>",
|
||||
lambda e, s=self: s.MiddleButtonPressEvent(e, 1, 1))
|
||||
self.bind("<ButtonRelease-2>",
|
||||
lambda e, s=self: s.MiddleButtonReleaseEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonRelease-2>",
|
||||
lambda e, s=self: s.MiddleButtonReleaseEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonRelease-2>",
|
||||
lambda e, s=self: s.MiddleButtonReleaseEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonRelease-2>",
|
||||
lambda e, s=self: s.MiddleButtonReleaseEvent(e, 1, 1))
|
||||
|
||||
# Right Button
|
||||
self.bind("<ButtonPress-3>",
|
||||
lambda e, s=self: s.RightButtonPressEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonPress-3>",
|
||||
lambda e, s=self: s.RightButtonPressEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonPress-3>",
|
||||
lambda e, s=self: s.RightButtonPressEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonPress-3>",
|
||||
lambda e, s=self: s.RightButtonPressEvent(e, 1, 1))
|
||||
self.bind("<ButtonRelease-3>",
|
||||
lambda e, s=self: s.RightButtonReleaseEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonRelease-3>",
|
||||
lambda e, s=self: s.RightButtonReleaseEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonRelease-3>",
|
||||
lambda e, s=self: s.RightButtonReleaseEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonRelease-3>",
|
||||
lambda e, s=self: s.RightButtonReleaseEvent(e, 1, 1))
|
||||
|
||||
if sys.platform == 'win32':
|
||||
self.bind("<MouseWheel>",
|
||||
lambda e, s=self: s.MouseWheelEvent(e, 0, 0))
|
||||
self.bind("<Control-MouseWheel>",
|
||||
lambda e, s=self: s.MouseWheelEvent(e, 1, 0))
|
||||
self.bind("<Shift-MouseWheel>",
|
||||
lambda e, s=self: s.MouseWheelEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-MouseWheel>",
|
||||
lambda e, s=self: s.MouseWheelEvent(e, 1, 1))
|
||||
else:
|
||||
# Mouse wheel forward event
|
||||
self.bind("<ButtonPress-4>",
|
||||
lambda e, s=self: s.MouseWheelForwardEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonPress-4>",
|
||||
lambda e, s=self: s.MouseWheelForwardEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonPress-4>",
|
||||
lambda e, s=self: s.MouseWheelForwardEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonPress-4>",
|
||||
lambda e, s=self: s.MouseWheelForwardEvent(e, 1, 1))
|
||||
|
||||
# Mouse wheel backward event
|
||||
self.bind("<ButtonPress-5>",
|
||||
lambda e, s=self: s.MouseWheelBackwardEvent(e, 0, 0))
|
||||
self.bind("<Control-ButtonPress-5>",
|
||||
lambda e, s=self: s.MouseWheelBackwardEvent(e, 1, 0))
|
||||
self.bind("<Shift-ButtonPress-5>",
|
||||
lambda e, s=self: s.MouseWheelBackwardEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-ButtonPress-5>",
|
||||
lambda e, s=self: s.MouseWheelBackwardEvent(e, 1, 1))
|
||||
|
||||
# Key related events
|
||||
self.bind("<KeyPress>",
|
||||
lambda e, s=self: s.KeyPressEvent(e, 0, 0))
|
||||
self.bind("<Control-KeyPress>",
|
||||
lambda e, s=self: s.KeyPressEvent(e, 1, 0))
|
||||
self.bind("<Shift-KeyPress>",
|
||||
lambda e, s=self: s.KeyPressEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-KeyPress>",
|
||||
lambda e, s=self: s.KeyPressEvent(e, 1, 1))
|
||||
|
||||
self.bind("<KeyRelease>",
|
||||
lambda e, s=self: s.KeyReleaseEvent(e, 0, 0))
|
||||
self.bind("<Control-KeyRelease>",
|
||||
lambda e, s=self: s.KeyReleaseEvent(e, 1, 0))
|
||||
self.bind("<Shift-KeyRelease>",
|
||||
lambda e, s=self: s.KeyReleaseEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-KeyRelease>",
|
||||
lambda e, s=self: s.KeyReleaseEvent(e, 1, 1))
|
||||
|
||||
self.bind("<Enter>",
|
||||
lambda e, s=self: s.EnterEvent(e, 0, 0))
|
||||
self.bind("<Control-Enter>",
|
||||
lambda e, s=self: s.EnterEvent(e, 1, 0))
|
||||
self.bind("<Shift-Enter>",
|
||||
lambda e, s=self: s.EnterEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-Enter>",
|
||||
lambda e, s=self: s.EnterEvent(e, 1, 1))
|
||||
self.bind("<Leave>",
|
||||
lambda e, s=self: s.LeaveEvent(e, 0, 0))
|
||||
self.bind("<Control-Leave>",
|
||||
lambda e, s=self: s.LeaveEvent(e, 1, 0))
|
||||
self.bind("<Shift-Leave>",
|
||||
lambda e, s=self: s.LeaveEvent(e, 0, 1))
|
||||
self.bind("<Control-Shift-Leave>",
|
||||
lambda e, s=self: s.LeaveEvent(e, 1, 1))
|
||||
|
||||
self.bind("<Configure>", self.ConfigureEvent)
|
||||
self.bind("<Expose>",lambda e,s=self: s.ExposeEvent())
|
||||
|
||||
def CreateTimer(self, obj, evt):
|
||||
self.after(10, self._Iren.TimerEvent)
|
||||
|
||||
def DestroyTimer(self, obj, event):
|
||||
"""The timer is a one shot timer so will expire automatically."""
|
||||
return 1
|
||||
|
||||
def _GrabFocus(self, enter=0):
|
||||
self._OldFocus=self.focus_get()
|
||||
self.focus()
|
||||
|
||||
def MouseMoveEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.MouseMoveEvent()
|
||||
|
||||
def LeftButtonPressEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.LeftButtonPressEvent()
|
||||
if not self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
|
||||
def LeftButtonReleaseEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.LeftButtonReleaseEvent()
|
||||
|
||||
def MiddleButtonPressEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.MiddleButtonPressEvent()
|
||||
if not self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
|
||||
def MiddleButtonReleaseEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.MiddleButtonReleaseEvent()
|
||||
|
||||
def RightButtonPressEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.RightButtonPressEvent()
|
||||
if not self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
|
||||
def RightButtonReleaseEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.RightButtonReleaseEvent()
|
||||
|
||||
def MouseWheelEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
if event.delta > 0:
|
||||
self._Iren.MouseWheelForwardEvent()
|
||||
else:
|
||||
self._Iren.MouseWheelBackwardEvent()
|
||||
|
||||
def MouseWheelForwardEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.MouseWheelForwardEvent()
|
||||
|
||||
def MouseWheelBackwardEvent(self, event, ctrl, shift):
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, chr(0), 0, None)
|
||||
self._Iren.MouseWheelBackwardEvent()
|
||||
|
||||
def KeyPressEvent(self, event, ctrl, shift):
|
||||
key = chr(0)
|
||||
if event.keysym_num < 128:
|
||||
key = chr(event.keysym_num)
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, key, 0, event.keysym)
|
||||
self._Iren.KeyPressEvent()
|
||||
self._Iren.CharEvent()
|
||||
|
||||
def KeyReleaseEvent(self, event, ctrl, shift):
|
||||
key = chr(0)
|
||||
if event.keysym_num < 128:
|
||||
key = chr(event.keysym_num)
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl,
|
||||
shift, key, 0, event.keysym)
|
||||
self._Iren.KeyReleaseEvent()
|
||||
|
||||
def ConfigureEvent(self, event):
|
||||
oldwidth, oldheight = self._Iren.GetSize()
|
||||
self._Iren.SetSize(event.width, event.height)
|
||||
self._Iren.ConfigureEvent()
|
||||
# check whether if the window has expanded vs shrunk
|
||||
if event.width <= oldwidth and event.height <= oldheight:
|
||||
# there will be no ExposeEvent if the window didn't grow,
|
||||
# so post a render to occur after any event processing
|
||||
self.after(0, self.Render)
|
||||
|
||||
def EnterEvent(self, event, ctrl, shift):
|
||||
if self._FocusOnEnter:
|
||||
self._GrabFocus()
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl, shift,
|
||||
chr(0), 0, None)
|
||||
self._Iren.EnterEvent()
|
||||
|
||||
def LeaveEvent(self, event, ctrl, shift):
|
||||
if self._FocusOnEnter and (self._OldFocus != None):
|
||||
self._OldFocus.focus()
|
||||
self._Iren.SetEventInformationFlipY(event.x, event.y, ctrl, shift,
|
||||
chr(0), 0, None)
|
||||
self._Iren.LeaveEvent()
|
||||
|
||||
def ExposeEvent(self):
|
||||
if (not self.__InExpose):
|
||||
self.__InExpose = 1
|
||||
if (not self._RenderWindow.IsA('vtkCocoaRenderWindow')):
|
||||
self.update()
|
||||
self._RenderWindow.Render()
|
||||
self.__InExpose = 0
|
||||
|
||||
def GetRenderWindow(self):
|
||||
addr = self.tk.call(self._w, 'GetRenderWindow')[5:]
|
||||
return vtkRenderWindow('_%s_vtkRenderWindow_p' % addr)
|
||||
|
||||
def Render(self):
|
||||
self._RenderWindow.Render()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
def vtkRenderWindowInteractorConeExample():
|
||||
"""Like it says, just a simple example
|
||||
"""
|
||||
|
||||
from vtkmodules.vtkFiltersSources import vtkConeSource
|
||||
from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer
|
||||
# load implementations for rendering and interaction factory classes
|
||||
import vtkmodules.vtkRenderingOpenGL2
|
||||
import vtkmodules.vtkInteractionStyle
|
||||
|
||||
# create root window
|
||||
root = tkinter.Tk()
|
||||
|
||||
# create vtkTkRenderWidget
|
||||
pane = vtkTkRenderWindowInteractor(root, width=300, height=300)
|
||||
pane.Initialize()
|
||||
|
||||
def quit(obj=root):
|
||||
obj.quit()
|
||||
|
||||
pane.AddObserver("ExitEvent", lambda o,e,q=quit: q())
|
||||
|
||||
ren = vtkRenderer()
|
||||
pane.GetRenderWindow().AddRenderer(ren)
|
||||
|
||||
cone = vtkConeSource()
|
||||
cone.SetResolution(8)
|
||||
|
||||
coneMapper = vtkPolyDataMapper()
|
||||
coneMapper.SetInputConnection(cone.GetOutputPort())
|
||||
|
||||
coneActor = vtkActor()
|
||||
coneActor.SetMapper(coneMapper)
|
||||
|
||||
ren.AddActor(coneActor)
|
||||
|
||||
# pack the pane into the tk root
|
||||
pane.pack(fill='both', expand=1)
|
||||
pane.Start()
|
||||
|
||||
# start the tk mainloop
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
vtkRenderWindowInteractorConeExample()
|
||||
Reference in New Issue
Block a user