WxPython and Vispy

628 views Asked by At

here a question on embedding Vispy's SceneCanvas in a WxPython application. How to resize SceneCanvas to fit panel? and resize again when resize the window?

You can try this code. If you maximize the window, you see the blue background. The size of OpenGL canvas doesn't change.

import wx
import vispy.scene as scene


class Canvas(scene.SceneCanvas):
    def __init__(self, *a, **k):
        scene.SceneCanvas.__init__(self, *a, **k)
        view = self.central_widget.add_view()
        view.bgcolor = '#ef00ef'
        self.show()


class my_panel_1(wx.Panel):
    def __init__(self, *a, **k):
        wx.Panel.__init__(self, *a, **k)
        self.SetBackgroundColour(wx.BLUE)
        self.canvas = Canvas(app="wx", parent=self)


class my_panel_2(wx.Panel):
    def __init__(self, *a, **k):
        wx.Panel.__init__(self, *a, **k)
        self.SetBackgroundColour(wx.GREEN)
        a_text = wx.TextCtrl(self, pos=(10, 10))
        a_button = wx.Button(self, -1, 'Hello Word', pos=(10, 50))


class MyFrame(wx.Frame):
    def __init__(self, *a, **k):
        wx.Frame.__init__(self, *a, **k, title="Title", size=(800, 600))

        box = wx.BoxSizer(wx.HORIZONTAL)

        panel1 = my_panel_1(self)
        box.Add(panel1, 1, wx.EXPAND)

        box2 = wx.BoxSizer(wx.VERTICAL)
        box.Add(box2, 0, wx.EXPAND)

        panel2 = my_panel_2(self)
        box2.Add(panel2, 1, wx.EXPAND)

        self.SetAutoLayout(True)
        self.SetSizer(box)
        self.Layout()


if __name__ == '__main__':
    app = wx.App(False)
    frame = MyFrame(None)
    frame.Show(True)
    app.MainLoop()

If can be useful, my configuration is:

  • Linux Rebecca
  • Python 3.6.4
  • WxPython 4.0.1
  • Vispy 0.6.0
1

There are 1 answers

0
Francesco Faccenda On

I solved this problem by manually adapting the canvas size to the panel size when the event wx.EVT_SIZE is fired. For example, in your my_panel_1 define:

def adapt_canvas_size(self):
    w, h = self.GetSize()
    self.canvas.size = (w,h)

You might also want to call this through a wx.CallAfter()

However, I also found a bug in the vispy lib that I solved overwriting the related function:

import vispy.app.backends._wx as wx_backend

def _vispy_set_size_fixed(self, w, h):
    # Set size of the widget or window
    if not self._init:
        self._size_init = (w, h)
    if hasattr(self, 'SetSize'):
        # phoenix
        self.SetSize([w, h]) # bugfix: pass an array as single argument to the SetSize, not two values as two arguments!
    else:
        # legacy
        self.SetSizeWH(w, h)

# override the related library function which appear to be bugged  
wx_backend.CanvasBackend._vispy_set_size = _vispy_set_size_fixed

The bug was passing a couple of element to the self.SetSize(w, h) instead of a single array with required dimension self.SetSize([w, h]).

Hope this helps, best regards, Francesco