Я пишу приложение для визуализации облака точек в VTK с использованием графического интерфейса wxPython.Я основал код на превосходных примерах Сухбиндера Сингха здесь и здесь .Теперь я хотел бы реализовать опцию щелчка правой кнопкой мыши на моей панели данных, которая позволяет пользователю выполнять различные задачи (например, сбросить положение камеры) через контекстное меню.Я пробовал несколько разных сценариев, но поведение в каждом из них немного неправильное:
A) Событие "RightButtonPressEvent" позволяет мне выбрать нужный элемент из моего контекстного меню и выполняет связанную функцию,но затем больше не будет реагировать на левую кнопку мыши, и
B) событие "RightButtonReleaseEvent" также приведет к выполнению связанной функции, но тогда любое последующее движение мыши будет действовать так, как если бы у меня все еще былоправая кнопка нажата.В моем текущем стиле интерактивного окна визуализации VTK это означает увеличение / уменьшение масштаба - пока я не нажму левую кнопку мыши.
Я пытался (B) с последующим вызовом PostEvent для имитации щелчка левой кнопкой мыши, но безрезультатно.Добавление события непосредственно к интерактору, а не к его стилю имеет тот же эффект.Кто-нибудь может сказать мне, что мне не хватает?
Использование Python 3.4 / 3.6 на Win7, wx 4.0.3, vtk 8.1.1.
Мой длинный пример "минимального" ниже:
import wx
import vtk
from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor
import numpy as np
class VtkPointCloud:
def __init__(self, zMin=-10.0, zMax=10.0):
self.maxNumPoints = 1e6
self.vtkPolyData = vtk.vtkPolyData()
self.clearPoints()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
def addPoint(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def clearPoints(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkDepth = vtk.vtkDoubleArray()
self.vtkDepth.SetName('DepthArray')
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
class p1(wx.Panel):
# ---------------------------------------------------------------------------------------------
def __init__(self,parent):
wx.Panel.__init__(self, parent)
self.widget = wxVTKRenderWindowInteractor(self, -1)
self.widget.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
self.widget.Enable(1)
self.widget.AddObserver("ExitEvent", lambda o,e,f=self: f.Close())
i_style = self.widget.GetInteractorStyle()
#i_style.AddObserver("RightButtonPressEvent", self._context_menu) # Freezes panel!
i_style.AddObserver("RightButtonReleaseEvent", self._context_menu)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.widget, 1, wx.EXPAND)
self.SetSizer(self.sizer)
self.Layout()
self.is_plotted = False
# ---------------------------------------------------------------------------------------------
def renderthis(self):
# open a window and create a renderer
pointCloud = VtkPointCloud()
data = 20*(np.random.rand(3,1000)-0.5)
for i in range(data.shape[1]):
pointCloud.addPoint(data[:,i])
camera = vtk.vtkCamera()
midpoint_x = 0
midpoint_y = 0
camera.SetPosition(midpoint_x, midpoint_y, -np.nanmax(data[2,:])); # eye position
camera.SetFocalPoint(midpoint_x, midpoint_y, np.nanmax(data[2,:])) # perspective vanishing point
# Save the default view
self._default_cam_pos = camera.GetPosition()
self._default_cam_focal = camera.GetFocalPoint()
self._default_view_up = camera.GetViewUp()
# Renderer
self._renderer = vtk.vtkRenderer()
self._renderer.AddActor(pointCloud.vtkActor)
self._renderer.SetBackground(0.0, 0.0, 0.0)
self._renderer.SetActiveCamera(camera)
# Render Window
self.widget.GetRenderWindow().AddRenderer(self._renderer)
# ---------------------------------------------------------------------------------------------
def _context_menu(self, caller, event):
reset_cam_ID = wx.NewId()
self.Bind(wx.EVT_MENU, self._on_reset_cam, id=reset_cam_ID)
menu = wx.Menu()
menu.Append(reset_cam_ID, "Reset camera")
self.PopupMenu(menu)
menu.Destroy()
# ---------------------------------------------------------------------------------------------
def _on_reset_cam(self, event):
cam = self._renderer.GetActiveCamera()
cam.SetPosition(self._default_cam_pos)
cam.SetFocalPoint(self._default_cam_focal)
cam.SetViewUp(self._default_view_up)
self.Refresh()
class TestFrame(wx.Frame):
# ---------------------------------------------------------------------------------------------
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(650,600),
style=(wx.MINIMIZE_BOX |
wx.SYSTEM_MENU |
wx.CAPTION |
wx.CLOSE_BOX |
wx.CLIP_CHILDREN))
self.sp = wx.SplitterWindow(self)
self.p1 = p1(self.sp)
self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
self.sp.SplitHorizontally(self.p1, self.p2, 470)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText("Click on the Plot Button")
self.plotbut = wx.Button(self.p2, -1, "Plot", size=(40,20), pos=(10,10))
self.plotbut.Bind(wx.EVT_BUTTON,self.plot)
# ---------------------------------------------------------------------------------------------
def plot(self,event):
if not self.p1.is_plotted:
self.p1.renderthis()
self.statusbar.SetStatusText("Use your mouse to interact with the model")
app = wx.App(redirect=False)
frame = TestFrame(None, "Pointcloud")
frame.Show()
app.MainLoop()