在wxPanel中的VTK中完成鼠标事件操作

时间:2018-11-12 21:22:35

标签: wxpython vtk

我正在编写一个使用wxPython GUI在VTK中渲染点云的应用程序。我基于Sukhbinder Singh herehere的出色示例编写了代码。我现在想在数据面板中实现鼠标右键单击选项,该选项允许用户通过上下文菜单执行各种任务(例如重置相机位置)。我尝试了几种不同的情况,但是每种情况下的行为都略有错误:

A)事件“ RightButtonPressEvent”使我可以从上下文菜单中选择合适的项目并执行绑定功能,但随后将不再响应鼠标左键,并且

B)事件“ RightButtonReleaseEvent”也开始执行绑定功能,但是随后鼠标的任何移动都好像我仍然按下右键一样。在我当前的VTK渲染窗口交互器样式中,这意味着放大/缩小-直到单击鼠标左键。

我尝试了(B)随后的PostEvent调用来模拟鼠标左键单击,但无济于事。将事件直接添加到交互器而不是其样式具有相同的效果。谁能告诉我我所缺少的吗?

在Win7,wx 4.0.3,vtk 8.1.1。上使用Python 3.4 / 3.6

我的长期“最小”示例如下:

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()

0 个答案:

没有答案