updated wxMVCTree, VTK, and the demo

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4629 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
1999-11-19 05:34:40 +00:00
parent 5008c64c32
commit e395c057a3
6 changed files with 386 additions and 238 deletions

View File

@@ -45,6 +45,15 @@ Or you can send mail directly to the list using this address:
---------------------------------------------------------------------- ----------------------------------------------------------------------
What's new in 2.1.12
--------------------
Updated wxMVCTree and added a demo for it.
Added a wrapper class for the Visualization ToolKit (or VTK) in the
wxPython.lib.vtk module. (http://www.kitware.com/)
What's new in 2.1.11 What's new in 2.1.11
-------------------- --------------------

View File

@@ -21,6 +21,8 @@ _useSplitter = true
_useNestedSplitter = true _useNestedSplitter = true
_treeList = [ _treeList = [
('New since last release', ['wxMVCTree', 'wxVTKRenderWindow']),
('Managed Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame']), ('Managed Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame']),
('Non-Managed Windows', ['wxGrid', 'wxSashWindow', ('Non-Managed Windows', ['wxGrid', 'wxSashWindow',
@@ -47,7 +49,7 @@ _treeList = [
('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog', ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar', 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
'PyShell', 'wxCalendar']), 'PyShell', 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow']),
('Cool Contribs', ['pyTree', 'hangman', 'SlashDot', 'XMLtreeview']), ('Cool Contribs', ['pyTree', 'hangman', 'SlashDot', 'XMLtreeview']),

View File

@@ -0,0 +1,61 @@
import sys, os
from wxPython.wx import *
from wxPython.lib.mvctree import *
logger = None
def selchanging(evt):
logger.write("SelChanging!\n")
def selchanged(evt):
logger.write("SelChange!\n")
logger.write(str(evt.node))
def expanded(evt):
logger.write("Expanded\n")
def closed(evt):
logger.write("Closed!\n")
def key(evt):
logger.write("Key\n")
def add(evt):
logger.write("Add\n")
def delitem(evt):
logger.write("Delete\n")
def runTest(frame, nb, log):
#f = wxFrame(frame, -1, "wxMVCTree", wxPoint(0,0), wxSize(200,500))
global logger
logger = log
p = wxMVCTree(nb, -1)
p.SetAssumeChildren(true)
p.SetModel(LateFSTreeModel(os.path.normpath(os.getcwd() + os.sep +'..')))
#Uncomment this to enable live filename editing!
# p.AddEditor(FileEditor(p))
p.SetMultiSelect(true)
EVT_MVCTREE_SEL_CHANGING(p, p.GetId(), selchanging)
EVT_MVCTREE_SEL_CHANGED(p, p.GetId(), selchanged)
EVT_MVCTREE_ITEM_EXPANDED(p, p.GetId(), expanded)
EVT_MVCTREE_ITEM_COLLAPSED(p, p.GetId(), closed)
EVT_MVCTREE_ADD_ITEM(p, p.GetId(), add)
EVT_MVCTREE_DELETE_ITEM(p, p.GetId(), delitem)
EVT_MVCTREE_KEY_DOWN(p, p.GetId(), key)
return p
overview = """\
wxMVCTree is a control which handles hierarchical data. It is constructed in model-view-controller architecture, so the display of that data, and the content of the data can be changed greatly without affecting the other parts.
Multiple selections are possible by holding down the Ctrl key.
This demo shows the wxPython directory structure. The interesting part is that the tree model is late-bound to the filesystem, so the filenames are not retrieved until the directory is expanded. In mvctree.py are models for generic data, and both the early and late-bound filesystem models.
There is also support for editing, though it's not enabled in this demo, to avoid accidentally renaming files!
"""

View File

@@ -0,0 +1,60 @@
from wxPython.wx import *
try:
from wxPython.lib import vtk
haveVTK = true
except ImportError:
haveVTK = false
#----------------------------------------------------------------------
def runTest(frame, nb, log):
if haveVTK:
win = vtk.wxVTKRenderWindow(nb, -1)
# Get the render window
renWin = win.GetRenderWindow()
# Next, do the VTK stuff
ren = vtk.vtkRenderer()
renWin.AddRenderer(ren)
cone = vtk.vtkConeSource()
cone.SetResolution(80)
coneMapper = vtk.vtkPolyDataMapper()
coneMapper.SetInput(cone.GetOutput())
coneActor = vtk.vtkActor()
coneActor.SetMapper(coneMapper)
ren.AddActor(coneActor)
coneMapper.GetLookupTable().Build()
# Create a scalar bar
scalarBar = vtk.vtkScalarBarActor()
scalarBar.SetLookupTable(coneMapper.GetLookupTable())
scalarBar.SetTitle("Temperature")
scalarBar.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport()
scalarBar.GetPositionCoordinate().SetValue(0.1, 0.01)
scalarBar.SetOrientationToHorizontal()
scalarBar.SetWidth(0.8)
scalarBar.SetHeight(0.17)
ren.AddActor2D(scalarBar)
return win
else:
wxMessageBox("Unable to import VTK, which is a required component "
"of this demo. You need to download and install the "
"Python extension module for VTK from http://www.kitware.com/",
"Import Error")
return None
#----------------------------------------------------------------------
overview = """\
wxVTKRenderWindow is a wrapper around the vtkRenderWindow from the
VTK Visualization Toolkit. The VTK Python extensions are required,
they can be obtained from http://www.kitware.com/ where you can also
find some nifty pictures and stuff.
"""

View File

@@ -2,10 +2,8 @@
wxMVCTree is a control which handles hierarchical data. It is constructed wxMVCTree is a control which handles hierarchical data. It is constructed
in model-view-controller architecture, so the display of that data, and in model-view-controller architecture, so the display of that data, and
the content of the data can be changed greatly without affecting the other parts. the content of the data can be changed greatly without affecting the other parts.
This module contains the wxMVCTree class (the 'controller' of the MVC trio)
and PathfinderNode, which it uses internally to manage its info.
Pathfinder actually is even more configurable than MVC normally implies, because wxMVCTree actually is even more configurable than MVC normally implies, because
almost every aspect of it is pluggable: almost every aspect of it is pluggable:
wxMVCTree - Overall controller, and the window that actually gets placed wxMVCTree - Overall controller, and the window that actually gets placed
in the GUI. in the GUI.
@@ -24,7 +22,7 @@ Author/Maintainer - Bryn Keller <xoltar@starship.python.net>
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from wxPython.wx import * from wxPython.wx import *
import os, sys import os, sys, traceback
#------------------------------------------------------------------------ #------------------------------------------------------------------------
class MVCTreeNode: class MVCTreeNode:
@@ -94,6 +92,8 @@ class LayoutEngine:
self.tree = tree self.tree = tree
def layout(self, node): def layout(self, node):
raise NotImplementedError raise NotImplementedError
def GetNodeList(self):
raise NotImplementedError
class Transform: class Transform:
""" """
@@ -110,6 +110,13 @@ class Transform:
""" """
raise NotImplementedError raise NotImplementedError
def GetSize(self):
"""
Returns the size of the entire tree as laid out and transformed
as a tuple
"""
raise NotImplementedError
class Painter: class Painter:
""" """
This is the interface that wxMVCTree expects from painters. All painters should This is the interface that wxMVCTree expects from painters. All painters should
@@ -122,9 +129,7 @@ class Painter:
self.fgcolor = wxNamedColour("BLUE") self.fgcolor = wxNamedColour("BLUE")
self.linecolor = wxNamedColour("GREY") self.linecolor = wxNamedColour("GREY")
self.font = wxFont(9, wxDEFAULT, wxNORMAL, wxNORMAL, false) self.font = wxFont(9, wxDEFAULT, wxNORMAL, wxNORMAL, false)
self.knobs = [] self.bmp = None
self.rectangles = []
self.minx = self.maxx = self.miny = self.maxy = 0
def GetFont(self): def GetFont(self):
return self.font return self.font
@@ -132,8 +137,11 @@ class Painter:
def SetFont(self, font): def SetFont(self, font):
self.font = font self.font = font
self.tree.Refresh() self.tree.Refresh()
def GetBuffer(self):
def paint(self, dc, node): return self.bmp
def ClearBuffer(self):
self.bmp = None
def paint(self, dc, node, doubleBuffered=1, paintBackground=1):
raise NotImplementedError raise NotImplementedError
def GetTextColour(self): def GetTextColour(self):
return self.textcolor return self.textcolor
@@ -177,19 +185,20 @@ class Painter:
return self.linebrush return self.linebrush
def OnMouse(self, evt): def OnMouse(self, evt):
if evt.LeftDClick(): if evt.LeftDClick():
x, y = self.tree.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
for item in self.rectangles: for item in self.rectangles:
if item[1].contains((evt.GetX(), evt.GetY())): if item[1].contains((x,y)):
self.tree.Edit(item[0].data) self.tree.Edit(item[0].data)
self.tree.OnNodeClick(item[0], evt) self.tree.OnNodeClick(item[0], evt)
return return
elif evt.ButtonDown(): elif evt.ButtonDown():
#self.oldpos = (evt.GetX(), evt.GetY()) x, y = self.tree.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
for item in self.rectangles: for item in self.rectangles:
if item[1].contains((evt.GetX(), evt.GetY())): if item[1].contains((x, y)):
self.tree.OnNodeClick(item[0], evt) self.tree.OnNodeClick(item[0], evt)
return return
for item in self.knobs: for item in self.knobs:
if item[1].contains((evt.GetX(), evt.GetY())): if item[1].contains((x, y)):
self.tree.OnKnobClick(item[0]) self.tree.OnKnobClick(item[0])
return return
evt.Skip() evt.Skip()
@@ -331,7 +340,8 @@ class FileEditor(Editor):
self.editcomp.SetSelection(0, len(node.fileName)) self.editcomp.SetSelection(0, len(node.fileName))
self.editcomp.SetFocus() self.editcomp.SetFocus()
self.treenode = treenode self.treenode = treenode
EVT_KEY_DOWN(self.editcomp, self._key) # EVT_KEY_DOWN(self.editcomp, self._key)
EVT_KEY_UP(self.editcomp, self._key)
EVT_LEFT_DOWN(self.editcomp, self._mdown) EVT_LEFT_DOWN(self.editcomp, self._mdown)
self.editcomp.CaptureMouse() self.editcomp.CaptureMouse()
@@ -347,10 +357,11 @@ class FileEditor(Editor):
os.rename(node.path + os.sep + node.fileName, node.path + os.sep + self.editcomp.GetValue()) os.rename(node.path + os.sep + node.fileName, node.path + os.sep + self.editcomp.GetValue())
node.fileName = self.editcomp.GetValue() node.fileName = self.editcomp.GetValue()
except: except:
import traceback;traceback.print_exc() traceback.print_exc()
self.editcomp.ReleaseMouse() self.editcomp.ReleaseMouse()
self.editcomp.Destroy() self.editcomp.Destroy()
del self.editcomp del self.editcomp
self.tree.Refresh()
def _key(self, evt): def _key(self, evt):
@@ -364,7 +375,6 @@ class FileEditor(Editor):
def _mdown(self, evt): def _mdown(self, evt):
if evt.IsButton(): if evt.IsButton():
pos = evt.GetPosition() pos = evt.GetPosition()
print pos.x, pos.y
edsize = self.editcomp.GetSize() edsize = self.editcomp.GetSize()
if pos.x < 0 or pos.y < 0 or pos.x > edsize.width or pos.y > edsize.height: if pos.x < 0 or pos.y < 0 or pos.x > edsize.width or pos.y > edsize.height:
self.EndEdit(false) self.EndEdit(false)
@@ -416,7 +426,6 @@ class LateFSTreeModel(FSTreeModel):
import string import string
name = string.split(path, os.sep)[-1] name = string.split(path, os.sep)[-1]
pathpart = path[:-len(name)] pathpart = path[:-len(name)]
print pathpart
fw = FileWrapper(pathpart, name) fw = FileWrapper(pathpart, name)
self._Build(path, fw) self._Build(path, fw)
self.SetRoot(fw) self.SetRoot(fw)
@@ -445,11 +454,19 @@ class StrTextConverter(TextConverter):
return str(node.data) return str(node.data)
class NullTransform(Transform): class NullTransform(Transform):
def GetSize(self):
return tuple(self.size)
def transform(self, node, offset, rotation): def transform(self, node, offset, rotation):
node.projx = node.x + offset[0] self.size = [0,0]
node.projy = node.y + offset[1] list = self.tree.GetLayoutEngine().GetNodeList()
for kid in node.kids: for node in list:
self.transform(kid, offset, rotation) node.projx = node.x + offset[0]
node.projy = node.y + offset[1]
if node.projx > self.size[0]:
self.size[0] = node.projx
if node.projy > self.size[1]:
self.size[1] = node.projy
class Rect: class Rect:
def __init__(self, x, y, width, height): def __init__(self, x, y, width, height):
@@ -485,17 +502,27 @@ class TreeLayout(LayoutEngine):
LayoutEngine.__init__(self, tree) LayoutEngine.__init__(self, tree)
self.NODE_STEP = 20 self.NODE_STEP = 20
self.NODE_HEIGHT = 20 self.NODE_HEIGHT = 20
self.nodelist = []
def layout(self, node): def layout(self, node):
self.nodelist = []
self.layoutwalk(node)
def GetNodeList(self):
return self.nodelist
def layoutwalk(self, node):
if node == self.tree.currentRoot: if node == self.tree.currentRoot:
node.level = 1 node.level = 1
self.lastY = (-self.NODE_HEIGHT) self.lastY = (-self.NODE_HEIGHT)
node.x = self.NODE_STEP * node.level node.x = self.NODE_STEP * node.level
node.y = self.lastY + self.NODE_HEIGHT node.y = self.lastY + self.NODE_HEIGHT
self.lastY = node.y self.lastY = node.y
self.nodelist.append(node)
if node.expanded: if node.expanded:
for kid in node.kids: for kid in node.kids:
kid.level = node.level + 1 kid.level = node.level + 1
self.layout(kid) self.layoutwalk(kid)
class TreePainter(Painter): class TreePainter(Painter):
""" """
@@ -515,7 +542,7 @@ class TreePainter(Painter):
self.textConverter = textConverter self.textConverter = textConverter
self.charWidths = [] self.charWidths = []
def paint(self, dc, node): def paint(self, dc, node, doubleBuffered=1, paintBackground=1):
if not self.charWidths: if not self.charWidths:
self.charWidths = [] self.charWidths = []
for i in range(25): for i in range(25):
@@ -530,15 +557,41 @@ class TreePainter(Painter):
self.fgbrush = wxBrush(self.GetForegroundColour(), wxSOLID) self.fgbrush = wxBrush(self.GetForegroundColour(), wxSOLID)
self.bgbrush = wxBrush(self.GetBackgroundColour(), wxSOLID) self.bgbrush = wxBrush(self.GetBackgroundColour(), wxSOLID)
self.linebrush = wxPen(self.GetLineColour(), 1, wxSOLID) self.linebrush = wxPen(self.GetLineColour(), 1, wxSOLID)
self.rectangles = [] treesize = self.tree.GetSize()
self.knobs = [] size = self.tree.transform.GetSize()
size = (max(treesize.width, size[0]+50), max(treesize.height, size[1]+50))
dc.BeginDrawing() dc.BeginDrawing()
dc.SetPen(self.GetBackgroundPen()) if doubleBuffered:
dc.SetBrush(self.GetBackgroundBrush()) mem_dc = wxMemoryDC()
size = self.tree.GetSize() if not self.GetBuffer():
dc.DrawRectangle(0, 0, size.width, size.height) self.knobs = []
if node: self.rectangles = []
self.paintWalk(node, dc) self.bmp = wxEmptyBitmap(size[0], size[1])
mem_dc.SelectObject(self.GetBuffer())
mem_dc.SetPen(self.GetBackgroundPen())
mem_dc.SetBrush(self.GetBackgroundBrush())
mem_dc.DrawRectangle(0, 0, size[0], size[1])
mem_dc.SetFont(self.tree.GetFont())
self.paintWalk(node, mem_dc)
else:
mem_dc.SelectObject(self.GetBuffer())
xstart, ystart = self.tree.CalcUnscrolledPosition(0,0)
size = self.tree.GetClientSizeTuple()
dc.Blit(xstart, ystart, size[0], size[1], mem_dc, xstart, ystart)
else:
if node == self.tree.currentRoot:
self.knobs = []
self.rectangles = []
dc.SetPen(self.GetBackgroundPen())
dc.SetBrush(self.GetBackgroundBrush())
dc.SetFont(self.tree.GetFont())
if paintBackground:
dc.DrawRectangle(0, 0, size[0], size[1])
if node:
#Call with not paintBackground because if we are told not to paint the
#whole background, we have to paint in parts to undo selection coloring.
pb = paintBackground
self.paintWalk(node, dc, not pb)
dc.EndDrawing() dc.EndDrawing()
def GetDashPen(self): def GetDashPen(self):
@@ -548,60 +601,57 @@ class TreePainter(Painter):
Painter.SetLinePen(self, pen) Painter.SetLinePen(self, pen)
self.dashpen = wxPen(pen.GetColour(), 1, wxDOT) self.dashpen = wxPen(pen.GetColour(), 1, wxDOT)
def drawBox(self, px, py, node, dc): def paintWalk(self, node, dc, paintRects=0):
if self.tree.model.IsLeaf(node.data) or ((node.expanded or not self.tree._assumeChildren) and not len(node.kids)):
return
dc.SetPen(self.linepen)
dc.SetBrush(self.bgbrush)
dc.DrawRectangle(px -4, py-4, 9, 9)
self.knobs.append(node, Rect(px -4, py -4, 9, 9))
dc.SetPen(self.textpen)
if not node.expanded:
dc.DrawLine(px, py -2, px, py + 3)
dc.DrawLine(px -2, py, px + 3, py)
def paintWalk(self, node, dc):
self.linePainter.paint(node.parent, node, dc) self.linePainter.paint(node.parent, node, dc)
self.nodePainter.paint(node, dc) self.nodePainter.paint(node, dc, drawRects = paintRects)
if node.expanded: if node.expanded:
for kid in node.kids: for kid in node.kids:
if not self.paintWalk(kid, dc): if not self.paintWalk(kid, dc, paintRects):
return false return false
for kid in node.kids: for kid in node.kids:
px = (kid.projx - self.tree.layout.NODE_STEP) + 5 px = (kid.projx - self.tree.layout.NODE_STEP) + 5
py = kid.projy + kid.height/2 py = kid.projy + kid.height/2
self.drawBox(px, py, kid, dc) if (not self.tree.model.IsLeaf(kid.data)) or ((kid.expanded or self.tree._assumeChildren) and len(kid.kids)):
dc.SetPen(self.linepen)
dc.SetBrush(self.bgbrush)
dc.DrawRectangle(px -4, py-4, 9, 9)
self.knobs.append(kid, Rect(px -4, py -4, 9, 9))
dc.SetPen(self.textpen)
if not kid.expanded:
dc.DrawLine(px, py -2, px, py + 3)
dc.DrawLine(px -2, py, px + 3, py)
if node == self.tree.currentRoot: if node == self.tree.currentRoot:
px = (node.projx - self.tree.layout.NODE_STEP) + 5 px = (node.projx - self.tree.layout.NODE_STEP) + 5
py = node.projy + node.height/2 py = node.projy + node.height/2
self.drawBox(px, py, node, dc) dc.SetPen(self.linepen)
dc.SetBrush(self.bgbrush)
dc.DrawRectangle(px -4, py-4, 9, 9)
self.knobs.append(node, Rect(px -4, py -4, 9, 9))
dc.SetPen(self.textpen)
if not node.expanded:
dc.DrawLine(px, py -2, px, py + 3)
dc.DrawLine(px -2, py, px + 3, py)
return true return true
def OnMouse(self, evt): def OnMouse(self, evt):
Painter.OnMouse(self, evt) Painter.OnMouse(self, evt)
class TreeNodePainter(NodePainter): class TreeNodePainter(NodePainter):
def paint(self, node, dc, location = None): def paint(self, node, dc, location = None, drawRects = 0):
text = self.painter.textConverter.convert(node) text = self.painter.textConverter.convert(node)
extent = dc.GetTextExtent(text) extent = dc.GetTextExtent(text)
node.width = extent[0] node.width = extent[0]
node.height = extent[1] node.height = extent[1]
if node == self.painter.tree.currentRoot:
self.painter.minx = self.painter.maxx = self.painter.miny = self.painter.maxy = 0
if node.projx < self.painter.minx:
self.painter.minx = node.projx
elif node.projx + node.width > self.painter.maxx:
self.painter.maxx = node.projx + node.width
if node.projy < self.painter.miny:
self.painter.miny = node.projy
elif node.projy + node.height > self.painter.maxy:
self.painter.maxy = node.projy + node.height
if node.selected: if node.selected:
dc.SetPen(self.painter.GetLinePen()) dc.SetPen(self.painter.GetLinePen())
dc.SetBrush(self.painter.GetForegroundBrush()) dc.SetBrush(self.painter.GetForegroundBrush())
dc.SetTextForeground(wxNamedColour("WHITE")) dc.SetTextForeground(wxNamedColour("WHITE"))
dc.DrawRectangle(node.projx -1, node.projy -1, node.width + 3, node.height + 3) dc.DrawRectangle(node.projx -1, node.projy -1, node.width + 3, node.height + 3)
else: else:
if drawRects:
dc.SetBrush(self.painter.GetBackgroundBrush())
dc.SetPen(self.painter.GetBackgroundPen())
dc.DrawRectangle(node.projx -1, node.projy -1, node.width + 3, node.height + 3)
dc.SetTextForeground(self.painter.GetTextColour()) dc.SetTextForeground(self.painter.GetTextColour())
dc.DrawText(text, node.projx, node.projy) dc.DrawText(text, node.projx, node.projy)
self.painter.rectangles.append((node, Rect(node.projx, node.projy, node.width, node.height))) self.painter.rectangles.append((node, Rect(node.projx, node.projy, node.width, node.height)))
@@ -612,7 +662,7 @@ class TreeLinePainter(LinePainter):
px = py = cx = cy = 0 px = py = cx = cy = 0
if parent is None or child == self.painter.tree.currentRoot: if parent is None or child == self.painter.tree.currentRoot:
px = (child.projx - self.painter.tree.layout.NODE_STEP) + 5 px = (child.projx - self.painter.tree.layout.NODE_STEP) + 5
py = child.projy + self.painter.tree.layout.NODE_HEIGHT/2 py = child.projy + self.painter.tree.layout.NODE_HEIGHT/2 -2
cx = child.projx cx = child.projx
cy = py cy = py
dc.DrawLine(px, py, cx, cy) dc.DrawLine(px, py, cx, cy)
@@ -620,7 +670,7 @@ class TreeLinePainter(LinePainter):
px = parent.projx + 5 px = parent.projx + 5
py = parent.projy + parent.height py = parent.projy + parent.height
cx = child.projx -5 cx = child.projx -5
cy = child.projy + self.painter.tree.layout.NODE_HEIGHT/2 cy = child.projy + self.painter.tree.layout.NODE_HEIGHT/2 -3
dc.DrawLine(px, py, px, cy) dc.DrawLine(px, py, px, cy)
dc.DrawLine(px, cy, cx, cy) dc.DrawLine(px, cy, cx, cy)
@@ -671,27 +721,35 @@ class wxMVCTreeEvent(wxPyCommandEvent):
self.node = node self.node = node
self.nodes = nodes self.nodes = nodes
self.keyEvent = keyEvent self.keyEvent = keyEvent
def GetNode(self):
return self.node
def GetNodes(self):
return self.nodes
def getKeyEvent(self):
return self.keyEvent
class wxMVCTreeNotifyEvent(wxMVCTreeEvent): class wxMVCTreeNotifyEvent(wxMVCTreeEvent):
def __init__(self, type, id, node = None, nodes = None, **kwargs): def __init__(self, type, id, node = None, nodes = None, **kwargs):
apply(wxMVCTreeEvent.__init__, (self, type, id), kwargs) apply(wxMVCTreeEvent.__init__, (self, type, id), kwargs)
self.notify = wxNotifyEvent(type, id) self.notify = wxNotifyEvent(type, id)
def getNotifyEvent(self):
return self.notify
class wxMVCTree(wxWindow): class wxMVCTree(wxScrolledWindow):
""" """
The main mvcTree class. The main mvc tree class.
""" """
def __init__(self, parent, id, model = None, layout = None, transform = None, def __init__(self, parent, id, model = None, layout = None, transform = None,
painter = None, *args, **kwargs): painter = None, *args, **kwargs):
apply(wxWindow.__init__, (self, parent, id), kwargs) apply(wxScrolledWindow.__init__, (self, parent, id), kwargs)
self.nodemap = {} self.nodemap = {}
self._multiselect = false self._multiselect = false
self._selections = [] self._selections = []
self._assumeChildren = false self._assumeChildren = false
self._scrollx = false self._scrollx = false
self._scrolly = false self._scrolly = false
self.doubleBuffered = true self.doubleBuffered = false
self._lastPhysicalSize = self.GetSize()
self._editors = [] self._editors = []
if not model: if not model:
model = BasicTreeModel() model = BasicTreeModel()
@@ -708,8 +766,22 @@ class wxMVCTree(wxWindow):
self.painter = painter self.painter = painter
self.SetFont(wxFont(9, wxDEFAULT, wxNORMAL, wxNORMAL, false)) self.SetFont(wxFont(9, wxDEFAULT, wxNORMAL, wxNORMAL, false))
EVT_MOUSE_EVENTS(self, self.OnMouse) EVT_MOUSE_EVENTS(self, self.OnMouse)
EVT_SCROLLWIN(self, self.OnScroll)
EVT_KEY_DOWN(self, self.OnKeyDown) EVT_KEY_DOWN(self, self.OnKeyDown)
self.doubleBuffered = true
def Refresh(self):
if self.doubleBuffered:
self.painter.ClearBuffer()
wxScrolledWindow.Refresh(self)
def GetPainter(self):
return self.painter
def GetLayoutEngine(self):
return self.layout
def GetTransform(self):
return self.transform
def __repr__(self): def __repr__(self):
return "<wxMVCTree instance at %s>" % str(hex(id(self))) return "<wxMVCTree instance at %s>" % str(hex(id(self)))
@@ -720,15 +792,16 @@ class wxMVCTree(wxWindow):
def NodeAdded(self, parent, child): def NodeAdded(self, parent, child):
e = wxMVCTreeEvent(wxEVT_MVCTREE_ADD_ITEM, self.GetId(), node = child, nodes = [parent, child]) e = wxMVCTreeEvent(wxEVT_MVCTREE_ADD_ITEM, self.GetId(), node = child, nodes = [parent, child])
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
self.painter.ClearBuffer()
def NodeInserted(self, parent, child, index): def NodeInserted(self, parent, child, index):
e = wxMVCTreeEvent(wxEVT_MVCTREE_ADD_ITEM, self.GetId(), node = child, nodes = [parent, child]) e = wxMVCTreeEvent(wxEVT_MVCTREE_ADD_ITEM, self.GetId(), node = child, nodes = [parent, child])
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
self.painter.ClearBuffer()
def NodeRemoved(self, node): def NodeRemoved(self, node):
e = wxMVCTreeEvent(wxEVT_MVCTREE_DELETE_ITEM, self.GetId(), node = child, nodes = [parent, child]) e = wxMVCTreeEvent(wxEVT_MVCTREE_DELETE_ITEM, self.GetId(), node = child, nodes = [parent, child])
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
self.painter.ClearBuffer()
def OnKeyDown(self, evt): def OnKeyDown(self, evt):
e = wxMVCTreeEvent(wxEVT_MVCTREE_KEY_DOWN, self.GetId(), keyEvent = evt) e = wxMVCTreeEvent(wxEVT_MVCTREE_KEY_DOWN, self.GetId(), keyEvent = evt)
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
@@ -738,7 +811,7 @@ class wxMVCTree(wxWindow):
dc = wxClientDC(self) dc = wxClientDC(self)
dc.SetFont(font) dc.SetFont(font)
self.layout.SetHeight(dc.GetTextExtent("")[1] + 18) self.layout.SetHeight(dc.GetTextExtent("")[1] + 18)
self.painter.ClearBuffer()
def GetFont(self): def GetFont(self):
return self.painter.GetFont() return self.painter.GetFont()
@@ -752,11 +825,10 @@ class wxMVCTree(wxWindow):
self.painter.OnMouse(evt) self.painter.OnMouse(evt)
def OnNodeClick(self, node, mouseEvent): def OnNodeClick(self, node, mouseEvent):
if node.selected: if node.selected and (self.IsMultiSelect() and mouseEvent.ControlDown()):
self.RemoveFromSelection(node.data) self.RemoveFromSelection(node.data)
else: else:
self.AddToSelection(node.data, mouseEvent.ControlDown()) self.AddToSelection(node.data, mouseEvent.ControlDown(), mouseEvent.ShiftDown())
self.Refresh()
def OnKnobClick(self, node): def OnKnobClick(self, node):
self.SetExpanded(node.data, not node.expanded) self.SetExpanded(node.data, not node.expanded)
@@ -793,6 +865,7 @@ class wxMVCTree(wxWindow):
self.currentRoot = self.layoutRoot self.currentRoot = self.layoutRoot
self.offset = [0,0] self.offset = [0,0]
self.rotation = 0 self.rotation = 0
self._scrollset = None
self.Refresh() self.Refresh()
def GetCurrentRoot(self): def GetCurrentRoot(self):
@@ -817,12 +890,11 @@ class wxMVCTree(wxWindow):
pass pass
def OnSize(self, evt): def OnSize(self, evt):
try: size = self.GetSize()
size = self.GetSizeTuple() self.center = (size.width/2, size.height/2)
self.center = (size[0]/2, size[1]/2) if self._lastPhysicalSize.width < size.width or self._lastPhysicalSize.height < size.height:
del self.bmp self.painter.ClearBuffer()
except: self._lastPhysicalSize = size
pass
def GetSelection(self): def GetSelection(self):
"Returns a tuple of selected nodes." "Returns a tuple of selected nodes."
@@ -909,7 +981,7 @@ class wxMVCTree(wxWindow):
def IsExpanded(self, node): def IsExpanded(self, node):
return self.nodemap[node].expanded return self.nodemap[node].expanded
def AddToSelection(self, nodeOrTuple, enableMulti = true): def AddToSelection(self, nodeOrTuple, enableMulti = true, shiftMulti = false):
nodeTuple = nodeOrTuple nodeTuple = nodeOrTuple
if type(nodeOrTuple)!= type(()): if type(nodeOrTuple)!= type(()):
nodeTuple = (nodeOrTuple,) nodeTuple = (nodeOrTuple,)
@@ -917,38 +989,68 @@ class wxMVCTree(wxWindow):
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
if not e.notify.IsAllowed(): if not e.notify.IsAllowed():
return return
if not self.IsMultiSelect() or not enableMulti: changeparents = []
if not (self.IsMultiSelect() and (enableMulti or shiftMulti)):
for node in self._selections: for node in self._selections:
treenode = self.nodemap[node] treenode = self.nodemap[node]
treenode.selected = false treenode.selected = false
changeparents.append(treenode)
node = nodeTuple[0] node = nodeTuple[0]
self._selections = [node] self._selections = [node]
treenode = self.nodemap[node] treenode = self.nodemap[node]
changeparents.append(treenode)
treenode.selected = true treenode.selected = true
else: else:
for node in nodeTuple: if shiftMulti:
try: for node in nodeTuple:
self._selections.index(node)
except ValueError:
self._selections.append(node)
treenode = self.nodemap[node] treenode = self.nodemap[node]
treenode.selected = true oldtreenode = self.nodemap[self._selections[0]]
if treenode.parent == oldtreenode.parent:
found = 0
for kid in oldtreenode.parent.kids:
if kid == treenode or kid == oldtreenode:
found = not found
kid.selected = true
self._selections.append(kid.data)
changeparents.append(kid)
elif found:
kid.selected = true
self._selections.append(kid.data)
changeparents.append(kid)
else:
for node in nodeTuple:
try:
self._selections.index(node)
except ValueError:
self._selections.append(node)
treenode = self.nodemap[node]
treenode.selected = true
changeparents.append(treenode)
e = wxMVCTreeEvent(wxEVT_MVCTREE_SEL_CHANGED, self.GetId(), nodeTuple[0], nodes = nodeTuple) e = wxMVCTreeEvent(wxEVT_MVCTREE_SEL_CHANGED, self.GetId(), nodeTuple[0], nodes = nodeTuple)
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
dc = wxClientDC(self)
self.PrepareDC(dc)
for node in changeparents:
if node:
self.painter.paint(dc, node, doubleBuffered = 0, paintBackground = 0)
self.painter.ClearBuffer()
def RemoveFromSelection(self, nodeTuple): def RemoveFromSelection(self, nodeTuple):
if type(nodeTuple) != type(()): if type(nodeTuple) != type(()):
nodeTuple = (nodeTuple,) nodeTuple = (nodeTuple,)
changeparents = []
for node in nodeTuple: for node in nodeTuple:
try: self._selections.remove(node)
self._selections.index(node) treenode = self.nodemap[node]
except IndexError: changeparents.append(treenode)
self._selections.remove(node) treenode.selected = false
treenode = self.nodemap[node]
node.selected = false
e = wxMVCTreeEvent(wxEVT_MVCTREE_SEL_CHANGED, self.GetId(), node, nodes = nodeTuple) e = wxMVCTreeEvent(wxEVT_MVCTREE_SEL_CHANGED, self.GetId(), node, nodes = nodeTuple)
self.GetEventHandler().ProcessEvent(e) self.GetEventHandler().ProcessEvent(e)
dc = wxClientDC(self)
self.PrepareDC(dc)
for node in changeparents:
if node:
self.painter.paint(dc, node, doubleBuffered = 0, paintBackground = 0)
self.painter.ClearBuffer()
def GetBackgroundColour(self): def GetBackgroundColour(self):
@@ -978,126 +1080,39 @@ class wxMVCTree(wxWindow):
def GetAssumeChildren(self): def GetAssumeChildren(self):
return self._assumeChildren return self._assumeChildren
def OnScroll(self, evt):
type = evt.GetEventType()
field = [self.painter.maxx - self.painter.minx, self.painter.maxy - self.painter.miny]
size = self.GetSizeTuple()
index = 1
if evt.GetOrientation() == wxHORIZONTAL:
index = 0
self._scrollx = true
else:
self._scrolly = true
index = 1
if type == wxEVT_SCROLLWIN_TOP:
self.offset[index] = 0
elif type == wxEVT_SCROLLWIN_LINEUP:
self.offset[index] = self.offset[index] + 1
elif type == wxEVT_SCROLLWIN_LINEDOWN:
self.offset[index] = self.offset[index] - 1
elif type == wxEVT_SCROLLWIN_PAGEUP:
self.offset[index] = self.offset[index] + int(20 * float(field[index])/float(size[index]))
elif type == wxEVT_SCROLLWIN_PAGEDOWN:
self.offset[index] = self.offset[index] - int(20 * float(field[index])/float(size[index]))
elif type == wxEVT_SCROLLWIN_THUMBTRACK:
self.offset[index] = -(evt.GetPosition())
elif type == wxEVT_SCROLLWIN_BOTTOM:
self.offset[index] = field[index]
self.transformed = false
self.Refresh()
def OnPaint(self, evt): def OnPaint(self, evt):
""" """
Ensures that the tree has been laid out and transformed, then calls the painter Ensures that the tree has been laid out and transformed, then calls the painter
to paint the control. to paint the control.
""" """
try: try:
self.EnableScrolling(false, false)
if not self.laidOut: if not self.laidOut:
self.layout.layout(self.currentRoot) self.layout.layout(self.currentRoot)
self.laidOut = true self.laidOut = true
self.transformed = false
if not self.transformed: if not self.transformed:
self.transform.transform(self.currentRoot, self.offset, self.rotation) self.transform.transform(self.currentRoot, self.offset, self.rotation)
self.transformed = true self.transformed = true
dc = wxPaintDC(self) tsize = None
dc.SetFont(self.GetFont()) tsize = list(self.transform.GetSize())
if self.doubleBuffered: tsize[0] = tsize[0] + 50
size = self.GetSize() tsize[1] = tsize[1] + 50
if not hasattr(self, 'bmp'):
self.bmp = bmp =wxEmptyBitmap(size.width, size.height)
else:
bmp = self.bmp
mem_dc = wxMemoryDC()
mem_dc.SetFont(self.GetFont())
mem_dc.SelectObject(bmp)
self.painter.paint(mem_dc, self.currentRoot)
dc.Blit(0, 0, size.width, size.height, mem_dc, 0, 0);
else:
self.painter.paint(dc, self.currentRoot)
size = self.GetSizeTuple() size = self.GetSizeTuple()
if self._scrollx or self.painter.minx < 0 or self.painter.maxx > size[0]: if tsize[0] > size[0] or tsize[1] > size[1]:
field = self.painter.maxx - self.painter.minx if not hasattr(self, '_oldsize') or (tsize[0] > self._oldsize[0] or tsize[1] > self._oldsize[1]):
self.SetScrollbar(wxHORIZONTAL, -self.offset[0], size[0]/field, field, true) self._oldsize = tsize
self._scrollx = false oldstart = self.ViewStart()
if self._scrolly or self.painter.miny < 0 or self.painter.maxy > size[1]: self._lastPhysicalSize = self.GetSize()
field = self.painter.maxy - self.painter.miny self.SetScrollbars(10, 10, tsize[0]/10, tsize[1]/10)
self.SetScrollbar(wxVERTICAL, -self.offset[1], size[1]/field, field, true) self.Scroll(oldstart[0], oldstart[1])
self._scrolly = false dc = wxPaintDC(self)
self.PrepareDC(dc)
dc.SetFont(self.GetFont())
self.painter.paint(dc, self.currentRoot, self.doubleBuffered)
except: except:
import traceback;traceback.print_exc() traceback.print_exc()
if __name__ == '__main__':
def exit(evt):
import sys;sys.exit()
block = 0
def selchanging(evt):
print "SelChanging!"
print evt.node
global block
if block:
evt.notify.Veto()
block = not block
def selchanged(evt):
print "SelChange!"
print evt.node
def expanded(evt):
print "Expanded!"
def closed(evt):
print "Closed!"
def key(evt):
print "Key"
def add(evt):
print "Add"
def delitem(evt):
print "Delete"
class MyApp(wxApp):
def OnInit(self):
f = wxFrame(NULL, -1, "wxMVCTree")
p = None
p = wxMVCTree(f, -1)
p.SetAssumeChildren(true)
if len(sys.argv) > 1:
p.SetModel(LateFSTreeModel(sys.argv[1]))
p.AddEditor(FileEditor(p))
p.SetMultiSelect(true)
f.Show(true)
EVT_CLOSE(f, exit)
EVT_MVCTREE_SEL_CHANGED(p, p.GetId(), selchanged)
EVT_MVCTREE_SEL_CHANGING(p, p.GetId(), selchanging)
EVT_MVCTREE_ITEM_EXPANDED(p, p.GetId(), expanded)
EVT_MVCTREE_ITEM_COLLAPSED(p, p.GetId(), closed)
EVT_MVCTREE_ADD_ITEM(p, p.GetId(), add)
EVT_MVCTREE_DELETE_ITEM(p, p.GetId(), delitem)
EVT_MVCTREE_KEY_DOWN(p, p.GetId(), key)
p.SetForegroundColour(wxNamedColour("GREEN"))
self.SetTopWindow(f)
return true
app = MyApp(false)
app.MainLoop()

View File

@@ -109,49 +109,50 @@ class wxVTKRenderWindow(wxWindow):
## testcode is now in the demo ##
if __name__ == '__main__': ## if __name__ == '__main__':
class TestFrame(wxFrame): ## class TestFrame(wxFrame):
def __init__(self, parent): ## def __init__(self, parent):
wxFrame.__init__(self, parent, -1, "VTK Test", size=(450,450)) ## wxFrame.__init__(self, parent, -1, "VTK Test", size=(450,450))
rw = wxVTKRenderWindow(self, -1) ## rw = wxVTKRenderWindow(self, -1)
# Get the render window ## # Get the render window
renWin = rw.GetRenderWindow() ## renWin = rw.GetRenderWindow()
# Next, do the VTK stuff ## # Next, do the VTK stuff
ren = vtkRenderer() ## ren = vtkRenderer()
renWin.AddRenderer(ren) ## renWin.AddRenderer(ren)
cone = vtkConeSource() ## cone = vtkConeSource()
cone.SetResolution(80) ## cone.SetResolution(80)
coneMapper = vtkPolyDataMapper() ## coneMapper = vtkPolyDataMapper()
coneMapper.SetInput(cone.GetOutput()) ## coneMapper.SetInput(cone.GetOutput())
coneActor = vtkActor() ## coneActor = vtkActor()
coneActor.SetMapper(coneMapper) ## coneActor.SetMapper(coneMapper)
ren.AddActor(coneActor) ## ren.AddActor(coneActor)
coneMapper.GetLookupTable().Build() ## coneMapper.GetLookupTable().Build()
# Create a scalar bar ## # Create a scalar bar
scalarBar = vtkScalarBarActor() ## scalarBar = vtkScalarBarActor()
scalarBar.SetLookupTable(coneMapper.GetLookupTable()) ## scalarBar.SetLookupTable(coneMapper.GetLookupTable())
scalarBar.SetTitle("Temperature") ## scalarBar.SetTitle("Temperature")
scalarBar.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() ## scalarBar.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport()
scalarBar.GetPositionCoordinate().SetValue(0.1, 0.01) ## scalarBar.GetPositionCoordinate().SetValue(0.1, 0.01)
scalarBar.SetOrientationToHorizontal() ## scalarBar.SetOrientationToHorizontal()
scalarBar.SetWidth(0.8) ## scalarBar.SetWidth(0.8)
scalarBar.SetHeight(0.17) ## scalarBar.SetHeight(0.17)
ren.AddActor2D(scalarBar) ## ren.AddActor2D(scalarBar)
class TestApp(wxApp): ## class TestApp(wxApp):
def OnInit(self): ## def OnInit(self):
f = TestFrame(None) ## f = TestFrame(None)
self.SetTopWindow(f) ## self.SetTopWindow(f)
f.Show(true) ## f.Show(true)
return true ## return true
app = TestApp(0) ## app = TestApp(0)
app.MainLoop() ## app.MainLoop()