如何在嵌入wxpython的vispy画布中向场景动态添加对象

如何在嵌入wxpython的vispy画布中向场景动态添加对象,python,wxpython,vispy,Python,Wxpython,Vispy,我想在按下按钮时添加一个箭头(某个对象)。该代码是vispy存储库中给出的示例的修改版本 import wx from vispy import scene from vispy.scene.visuals import Arrow import numpy as np class Canvas(scene.SceneCanvas): def __init__(self, *a, **k): sizes = k.pop("sizes", (300,

我想在按下按钮时添加一个箭头(某个对象)。该代码是vispy存储库中给出的示例的修改版本

import wx
from vispy import scene
from vispy.scene.visuals import Arrow

import numpy as np

class Canvas(scene.SceneCanvas):
    def __init__(self, *a, **k):
        sizes = k.pop("sizes", (300, 300))  # Default value is (300, 300)
        scene.SceneCanvas.__init__(self, *a, **k, size=sizes)
        view = self.central_widget.add_view()
        view.bgcolor = 'snow'
        view.camera = scene.TurntableCamera(up='+y', azimuth=100, elevation=15, fov=60)
        axis = scene.visuals.XYZAxis(parent=view.scene)
        
        arrow1 = np.array([(0, 0, 0, 1, 1, 0)])  # Arrow direction, position
        arr = Arrow(pos=np.array([(0, 0, 0), (1, 1, 0)]), color='teal', method='gl', width=5., arrows=arrow1,
                    arrow_type="angle_30", arrow_size=5.0, arrow_color='teal', antialias=True, parent=view.scene)
        
        self.show()

class mainFrame ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = "Add Object", pos = wx.DefaultPosition, size = wx.Size( 905,569 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )

        bSizer1 = wx.BoxSizer( wx.VERTICAL )

        self.panel_vispy = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer1.Add( self.panel_vispy, 9, wx.EXPAND |wx.ALL, 5 )

        self.panel_Buttons = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )


        bSizer2.Add( ( 0, 0), 1, wx.EXPAND, 5 )

        self.button_AddArrow = wx.Button( self.panel_Buttons, wx.ID_ANY, u"Add Arrow", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.button_AddArrow, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )


        bSizer2.Add( ( 0, 0), 1, wx.EXPAND, 5 )


        self.panel_Buttons.SetSizer( bSizer2 )
        self.panel_Buttons.Layout()
        bSizer2.Fit( self.panel_Buttons )
        bSizer1.Add( self.panel_Buttons, 1, wx.EXPAND |wx.ALL, 5 )


        self.SetSizer( bSizer1 )
        self.Layout()

        self.Centre( wx.BOTH )
        
        # Connect Events
        self.button_AddArrow.Bind(wx.EVT_BUTTON, self.button_AddArrow_OnClick)
        
        self.panel_vispy.canvas = Canvas(app="wx", parent=self, sizes=self.panel_vispy.GetSize())
    
    def button_AddArrow_OnClick(self, event):
        print("Adding arrow")
        arrow2 = np.array([(0, 0, 0, 1, 1, 0)])  # Arrow direction, position
        arr = Arrow(pos=np.array([(0, 0, 0), (1, 1, 0)]), color='red', method='gl', width=5., arrows=arrow2,
                    arrow_type="angle_30", arrow_size=5.0, arrow_color='red', antialias=True)#, parent=view.scene) -Unable to access view from the Canvas class


if __name__ == "__main__":
    app = wx.App(False)
    
    GUI = mainFrame(None)
    
    GUI.Show(True)
    
    app.MainLoop()
我已经创建了示例中给出的画布,并尝试从
大型机中实例化它。创建
画布
类的
初始化
中给出的所有对象。如果我想在按下按钮创建GUI后添加任何新对象,我无法从
大型机
访问
画布
类中的
视图
。或者有没有其他方法来实现这一点

更新: 以下是评论中给出的建议后的代码:

import wx
from vispy import scene, gloo
from vispy.scene.visuals import Arrow

import numpy as np

class Canvas(scene.SceneCanvas):
    def __init__(self, *a, **k):
        sizes = k.pop("sizes", (300, 300))  # Default value is (300, 300)
        scene.SceneCanvas.__init__(self, *a, **k, size=sizes)
        self.unfreeze()
        self.view = self.central_widget.add_view()
        self.view.bgcolor = 'snow'
        self.view.camera = scene.TurntableCamera(up='+y', azimuth=100, elevation=15, fov=60)
        axis = scene.visuals.XYZAxis(parent=self.view.scene)
        
        arrow1 = np.array([(0, 0, 0, 1, 1, 0)])  # Arrow direction, position
        arr = Arrow(pos=np.array([(0, 0, 0), (1, 1, 0)]), color='teal', method='gl', width=5., arrows=arrow1,
                    arrow_type="angle_30", arrow_size=5.0, arrow_color='teal', antialias=True, parent=self.view.scene)
        
        self.show()
    
class mainFrame ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = "Add Object", pos = wx.DefaultPosition, size = wx.Size( 905,569 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )

        bSizer1 = wx.BoxSizer( wx.VERTICAL )

        self.panel_vispy = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer1.Add( self.panel_vispy, 9, wx.EXPAND |wx.ALL, 5 )

        self.panel_Buttons = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )


        bSizer2.Add( ( 0, 0), 1, wx.EXPAND, 5 )

        self.button_AddArrow = wx.Button( self.panel_Buttons, wx.ID_ANY, u"Add Arrow", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.button_AddArrow, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )


        bSizer2.Add( ( 0, 0), 1, wx.EXPAND, 5 )


        self.panel_Buttons.SetSizer( bSizer2 )
        self.panel_Buttons.Layout()
        bSizer2.Fit( self.panel_Buttons )
        bSizer1.Add( self.panel_Buttons, 1, wx.EXPAND |wx.ALL, 5 )


        self.SetSizer( bSizer1 )
        self.Layout()

        self.Centre( wx.BOTH )
        
        # Connect Events
        self.button_AddArrow.Bind(wx.EVT_BUTTON, self.button_AddArrow_OnClick)
        
        self.panel_vispy.canvas = Canvas(app="wx", parent=self, sizes=self.panel_vispy.GetSize())
    
    def button_AddArrow_OnClick(self, event):
        print("Adding arrow")
        arrow2 = np.array([(0, 0, 0, 1, 1, 0)])  # Arrow direction, position
        arr = Arrow(pos=np.array([(0, 0, 0), (1, 1, 0)]), color='teal', method='gl', width=5., arrows=arrow2,
                    arrow_type="angle_30", arrow_size=5.0, arrow_color='teal', antialias=True, parent=self.panel_vispy.canvas.view.scene)
        self.panel_vispy.canvas.update() # Canvas not getting updated


if __name__ == "__main__":
    app = wx.App(False)
    
    GUI = mainFrame(None)
    
    GUI.Show(True)
    
    app.MainLoop()

代码现在运行时没有任何错误,这意味着可能添加了箭头,但场景没有更新。

根据@djoese和@RolfofSaxony的建议,我已经更新了代码。现在,代码在单击按钮时成功地添加了一个箭头

import wx
from vispy import scene, gloo
from vispy.scene.visuals import Arrow

import numpy as np

class Canvas(scene.SceneCanvas):
    def __init__(self, *a, **k):
        sizes = k.pop("sizes", (300, 300))  # Default value is (300, 300)
        scene.SceneCanvas.__init__(self, *a, **k, size=sizes)
        self.unfreeze()
        self.view = self.central_widget.add_view()
        self.view.bgcolor = 'snow'
        self.view.camera = scene.TurntableCamera(up='+y', azimuth=100, elevation=15, fov=60)
        axis = scene.visuals.XYZAxis(parent=self.view.scene)
        
        arrow1 = np.array([(0, 0, 0, 1, 1, 0)])  # Arrow direction, position
        arr = Arrow(pos=np.array([(0, 0, 0), (1, 1, 0)]), color='red', method='gl', width=5., arrows=arrow1,
                    arrow_type="angle_30", arrow_size=5.0, arrow_color='blue', antialias=True, parent=self.view.scene)
        
        self.show()
        
class mainFrame ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = "Add Object", pos = wx.DefaultPosition, size = wx.Size( 905,569 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )

        bSizer1 = wx.BoxSizer( wx.VERTICAL )

        self.panel_vispy = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer1.Add( self.panel_vispy, 9, wx.EXPAND |wx.ALL, 5 )

        self.panel_Buttons = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )


        bSizer2.Add( ( 0, 0), 1, wx.EXPAND, 5 )

        self.button_AddArrow = wx.Button( self.panel_Buttons, wx.ID_ANY, u"Add Arrow", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.button_AddArrow, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )


        bSizer2.Add( ( 0, 0), 1, wx.EXPAND, 5 )


        self.panel_Buttons.SetSizer( bSizer2 )
        self.panel_Buttons.Layout()
        bSizer2.Fit( self.panel_Buttons )
        bSizer1.Add( self.panel_Buttons, 1, wx.EXPAND |wx.ALL, 5 )


        self.SetSizer( bSizer1 )
        self.Layout()

        self.Centre( wx.BOTH )
        
        # Connect Events
        self.button_AddArrow.Bind(wx.EVT_BUTTON, self.button_AddArrow_OnClick)
        
        self.panel_vispy.canvas = Canvas(app="wx", parent=self, sizes=self.panel_vispy.GetSize())
    
    def button_AddArrow_OnClick(self, event):
        print("Adding arrow")
        arrow2 = np.array([(0, 0, 0, -1, -0.5, 1)])  # Arrow direction, position
        arr = Arrow(pos=np.array([(0, 0, 0), (-1, -0.5, 1)]), color='green', method='gl', width=5., arrows=arrow2,
                    arrow_type="angle_30", arrow_size=5.0, arrow_color='blue', antialias=True, parent=self.panel_vispy.canvas.view.scene)


if __name__ == "__main__":
    app = wx.App(False)
    
    GUI = mainFrame(None)
    
    GUI.Show(True)
    
    app.MainLoop()

看起来你已经注释掉了我认为可以使这项工作成功的主要因素;主要是
parent=view.scene
。您需要通过该父属性告诉可视内容应附加到何处。感谢您的回复。我只是注释掉了,这样示例python代码就可以毫无错误地运行了。问题是我无法从
画布
之外的其他类访问
视图
对象,这肯定会有助于可访问性,如果您在设置
self.view=
之后,按照@RolfofSaxony的建议,将
view
设置为
Canvas
实例
变量,即
self.view=
self.panel\u vispy.Canvas.view有什么问题?如果无法访问画布属性,则无法使用新的视觉效果更新画布。如果要与画布交互,您需要能够访问画布的某些部分。@djoese您是对的。这是一个令人尴尬的错误。我不知道这个错误是怎么发生的。通过添加
self.unfreeze()
,问题得以解决。我第一次使用箭头-花了一段时间我才弄清楚箭头的视觉效果,因此产生了混乱。谢谢你的耐心和帮助。我会尽快发布更新的工作代码。