wxPython: Creating a Grid with XRC

I recently tried to help someone (on the wxPython mailing list) figure out how to use a Grid widget (wx.grid.Grid) via XRC. It should be simple, but if you run the code below, you'll discover a weird issue:

import wx
from wx import xrc

########################################################################
class MyApp(wx.App):
    def OnInit(self):
        self.res = xrc.XmlResource("grid.xrc")
 
        frame = self.res.LoadFrame(None, 'MyFrame')
        panel = xrc.XRCCTRL(frame, "MyPanel")
        grid = xrc.XRCCTRL(panel, "MyGrid")
        print type(grid)
        grid.CreateGrid(25, 6)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 1, wx.EXPAND|wx.ALL, 5)
        
        panel.SetSizer(sizer)
 
        frame.Show()
        return True
 
if __name__ == "__main__":
    app = MyApp(False)
    app.MainLoop()

You'll note that when you run this, the type that is printed out is a "wx._windows.ScrolledWindow", not a Grid object. Thus you'll end up with the following traceback:

AttributeError: 'ScrolledWindow' object has no attribute 'CreateGrid'
File "c:\Users\mdriscoll\Desktop\xrcGridDemo.py", line 26, in 
  app = MyApp(False)
File "C:\Python26\Lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 7981, in __init__
  self._BootstrapApp()
File "C:\Python26\Lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 7555, in _BootstrapApp
  return _core_.PyApp__BootstrapApp(*args, **kwargs)
File "c:\Users\mdriscoll\Desktop\xrcGridDemo.py", line 14, in OnInit
  grid.CreateGrid(25, 6)

Now you may be wondering what's in the XRC file, so here's its contents:






As you can see, you should be getting a wxGrid back. What's the solution? You need to import wx.grid! See this thread for more information. According to Robin Dunn, creator of wxPython, here is the reason you need to do that:

You need to import wx.grid in your python code. When you do that then
some internal data structures are updated with the type info for the
grid classes, and this info is used when figuring out how to convert a
C++ pointer to a Python object of the right type for the XRCCTRL return
value.

Thus the updated code would look like this:

import wx
import wx.grid
from wx import xrc

########################################################################
class MyApp(wx.App):
    def OnInit(self):
        self.res = xrc.XmlResource("grid.xrc")
 
        frame = self.res.LoadFrame(None, 'MyFrame')
        panel = xrc.XRCCTRL(frame, "MyPanel")
        grid = xrc.XRCCTRL(panel, "MyGrid")
        print type(grid)
        grid.CreateGrid(25, 6)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 1, wx.EXPAND|wx.ALL, 5)
        
        panel.SetSizer(sizer)
 
        frame.Show()
        return True
 
if __name__ == "__main__":
    app = MyApp(False)
    app.MainLoop()

Now if you run into this oddball issue, you too will know what to do.

Related Articles

Copyright © 2022 Mouse Vs Python | Powered by Pythonlibrary