XRCed Question

I’ve followed the tutorial at http://wiki.wxpython.org/XRCed%20Component%20Plugins and have successfully added FloatSpin to the gizmo menu. (For backward compatibility reasons I’m using a stand-alone version of FloatSpin and not the one in agw.

However, when I save an xrc and try to load it in, I get the following error:

/usr/local/lib/wxPython-unicode-2.8.9.2/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/xrc.pyc in LoadFrame(*args, **kwargs)
147 def LoadFrame(*args, **kwargs):
148 “”“LoadFrame(self, Window parent, String name) -> wxFrame”""
–> 149 return _xrc.XmlResource_LoadFrame(*args, **kwargs)
150
151 def LoadOnFrame(*args, **kwargs):

PyAssertionError: C++ assertion “wxAssertFailure” failed at /BUILD/wxPython-src-2.8.9.2/src/common/sizer.cpp(379) in SetDimension(): can’t set size of uninitialized sizer item
WARNING: Failure executing file: <plot_set_editor.py>

This same error occurs with the TreeListCtrl that is already in the gizmos menu. I am fundamentally missing a step in the process, or is this some sort of bug? I’m on OS X 10.5, Python 2.5.4, wxPython 2.8.9.2.

I’m just learning XRCed and it seems great, but without the capability to add custom controls, it’s unfortunately not going to be very useful for me.

My component plugin files are:

xh_floatspin.py:

import wx
import wx.xrc as xrc
import FloatSpin as FS
class FloatSpinCtrlXmlHandler(xrc.XmlResourceHandler):
def init(self):
xrc.XmlResourceHandler.init(self)
# Standard styles
self.AddWindowStyles()
# Custom styles
self.AddStyle(‘FS_LEFT’, FS.FS_LEFT)
self.AddStyle(‘FS_RIGHT’, FS.FS_RIGHT)
self.AddStyle(‘FS_CENTRE’, FS.FS_CENTRE)
self.AddStyle(‘FS_READONLY’, FS.FS_READONLY)
def CanHandle(self,node):
return self.IsOfClass(node, ‘FloatSpin’)
# Process XML parameters and create the object
def DoCreateResource(self):
assert self.GetInstance() is None
try:
min_val = float(self.GetText(‘min_val’))
except:
min_val = None
try:
max_val = float(self.GetText(‘max_val’))
except:
max_val = None
try:
increment = float(self.GetText(‘increment’))
except:
increment = 1.0
w = FS.FloatSpin(parent = self.GetParentAsWindow(),
id = self.GetID(),
pos = self.GetPosition(),
size = self.GetSize(),
extrastyle=self.GetStyle(),
min_val=min_val,
max_val=max_val,
increment=increment)

    try:
        w.SetValue(float(self.GetText('value')))
    except:
        w.SetValue(0.0)
       
    try:
        w.SetDigits(int(self.GetText('digits')))
    except:
        pass
       
       
    self.SetupWindow(w)
    return w

floatspin.crx:

<?xml version="1.0" ?> control pos size value min_val max_val increment digits 1 FS_LEFT FS_RIGHT FS_CENTRE FS_READONLY EVT_FLOATSPIN xh_floatspin FloatSpinCtrlXmlHandler gizmo FloatSpin Floating Point SpinCtrl 10

The XRC file is
PlotSetEditor.xrc:

<?xml version="1.0" ?> 700,500 Plot Set Editor #00FF4A 1 1 0 0 wxEXPAND #0052FF vertical

My python script is
plot_set_editor.py:

import wx
import wx.xrc as xrc
from wx.gizmos import TreeListCtrl

if name == ‘main’:
if 1:
app = wx.App()
res=xrc.XmlResource ( ‘resources/PlotSetEditor.xrc’ )
mainFrame=res.LoadFrame( None, “plotSetEditor” )
mainFrame.Show()
app.MainLoop()

If anyone can give any insight as to whats going on, I’d appreciate it.

···

  • Rob Falck

Rob Falck wrote:

My python script is
plot_set_editor.py:

import wx
import wx.xrc as xrc
from wx.gizmos import TreeListCtrl

if __name__ == '__main__':
    if 1: app = wx.App()
        res=xrc.XmlResource ( 'resources/PlotSetEditor.xrc' )
        mainFrame=res.LoadFrame( None, "plotSetEditor" )
        mainFrame.Show() app.MainLoop()

If anyone can give any insight as to whats going on, I'd appreciate it.

You need to load the custom resource handler in your application code so XRC knows how to construct an object of that type. Something like this:

  res.InsertHandler(xh_floatspin.FloatSpinCtrlXmlHandler())

···

--
Robin Dunn
Software Craftsman

Thanks for your help, that got me past that roadblock. Now I'd like
to subclass the TreeListCtrl, I've saved its handler to
xh_TreeListCtrl.py and can start the app, but if I try to subclass it
using subclass="plotset_tree_ctrl.PlotSetTreeCtrl", I once again get
the PyAssertionError in sizer.cpp:

My script is:

import wx
import wx.xrc as xrc

from xh_TreeListCtrl import TreeListCtrlXmlHandler

if __name__ == '__main__':
    if 1:
        app = wx.App()
        res=xrc.XmlResource ( 'resources/PlotSetEditor.xrc' )
        res.InsertHandler(TreeListCtrlXmlHandler())
        mainFrame=res.LoadFrame( None, "plotSetEditor" )
        mainFrame.Show()
        app.MainLoop()

The offending xrc file is (remove the subclass from the TreeListCtrl
and it runs):

<?xml version="1.0" ?>
<resource>
  <object class="wxFrame" name="plotSetEditor">
    <object class="wxToolBar">
      <object class="wxButton" name="newButton">
        <label>New</label>
      </object>
      <object class="wxButton" name="saveButton">
        <label>Save</label>
      </object>
      <object class="wxButton" name="saveasButton">
        <label>Save As...</label>
      </object>
      <pos>0,0</pos>
      <size>50,50</size>
    </object>
    <object class="wxSplitterWindow">
      <object class="wxPanel" name="treePanel">
        <bg>#C1740E</bg>
        <object class="wxFlexGridSizer">
          <cols>1</cols>
          <rows>2</rows>
          <growablecols>0</growablecols>
          <growablerows>1</growablerows>
          <object class="sizeritem">
            <object class="wxStaticText">
              <label>Plot Set Editor</label>
              <style>wxALIGN_CENTRE</style>
            </object>
            <flag>wxALIGN_CENTRE</flag>
          </object>
          <object class="sizeritem">
            <object class="TreeListCtrl" name="plotsetTreeCtrl"
subclass="plotset_tree_ctrl.PlotSetTreeCtrl"/>
            <flag>wxALL|wxEXPAND</flag>
            <border>2</border>
          </object>
        </object>
      </object>
      <object class="wxPanel" name="editorPanel"/>
      <orientation>vertical</orientation>
      <sashpos>180</sashpos>
    </object>
    <size>500,500</size>
    <title>Plot Set Editor</title>
  </object>
</resource>

And the handler is in xh_TreeListCtrl:

import wx
import wx.xrc as xrc
import wx.gizmos as gizmos

class TreeListCtrlXmlHandler(xrc.XmlResourceHandler):
    def __init__(self):
        xrc.XmlResourceHandler.__init__(self)
        # Standard styles
        self.AddWindowStyles()
        # Custom styles
        self.AddStyle('wxDEFAULT_COL_WIDTH', gizmos.DEFAULT_COL_WIDTH)
        self.AddStyle('wxTL_MODE_NAV_FULLTREE',
gizmos.TL_MODE_NAV_FULLTREE)
        self.AddStyle('wxTL_MODE_NAV_EXPANDED',
gizmos.TL_MODE_NAV_EXPANDED)
        self.AddStyle('wxTL_MODE_NAV_VISIBLE',
gizmos.TL_MODE_NAV_VISIBLE)
        self.AddStyle('wxTL_MODE_NAV_LEVEL', gizmos.TL_MODE_NAV_LEVEL)
        self.AddStyle('wxTL_MODE_FIND_EXACT',
gizmos.TL_MODE_FIND_EXACT)
        self.AddStyle('wxTL_MODE_FIND_PARTIAL',
gizmos.TL_MODE_FIND_PARTIAL)
        self.AddStyle('wxTL_MODE_FIND_NOCASE',
gizmos.TL_MODE_FIND_NOCASE)
        self.AddStyle('wxTREE_HITTEST_ONITEMCOLUMN',
gizmos.TREE_HITTEST_ONITEMCOLUMN)
        self.AddStyle('wxTR_COLUMN_LINES', gizmos.TR_COLUMN_LINES)
        self.AddStyle('wxTR_VIRTUAL', gizmos.TR_VIRTUAL)
        self.AddStyle('wxTL_ALIGN_LEFT ', wx.ALIGN_LEFT)
        self.AddStyle('wxTL_ALIGN_RIGHT ', wx.ALIGN_RIGHT)
        self.AddStyle('wxTL_ALIGN_CENTER', wx.ALIGN_CENTER)

        self.AddStyle('wxTL_SEARCH_VISIBLE',
gizmos.TL_MODE_NAV_VISIBLE)
        self.AddStyle('wxTL_SEARCH_LEVEL ', gizmos.TL_MODE_NAV_LEVEL)
        self.AddStyle('wxTL_SEARCH_FULL ',
gizmos.TL_MODE_FIND_EXACT)
        self.AddStyle('wxTL_SEARCH_PARTIAL',
gizmos.TL_MODE_FIND_PARTIAL)
        self.AddStyle('wxTL_SEARCH_NOCASE ',
gizmos.TL_MODE_FIND_NOCASE)

        self.AddStyle('wxTR_DONT_ADJUST_MAC',
gizmos.TR_DONT_ADJUST_MAC)
        self.AddStyle('wxTR_DEFAULT_STYLE', wx.TR_DEFAULT_STYLE)

    def CanHandle(self, node):
        return self.IsOfClass(node, 'TreeListCtrl')

    # Process XML parameters and create the object
    def DoCreateResource(self):
        assert self.GetInstance() is None

        w = gizmos.TreeListCtrl(self.GetParentAsWindow(),
                                self.GetID(),
                                style=self.GetStyle(),
                                name=self.GetName())
        return w

As I see it I have a few work-around options. I can either fall back
to TreeCtrl and make do without the columns, or I can not subclass the
TreeListCtrl and Bind events and methods to it after its created. I'd
love to understand the correct way to do this, though.

I appreciate your patience.

···

On May 25, 4:57 pm, Robin Dunn <ro...@alldunn.com> wrote:

Rob Falck wrote:
> My python script is
> plot_set_editor.py:

> import wx
> import wx.xrc as xrc
> from wx.gizmos import TreeListCtrl

> if __name__ == '__main__':
> if 1:
> app = wx.App()
> res=xrc.XmlResource ( 'resources/PlotSetEditor.xrc' )
> mainFrame=res.LoadFrame( None, "plotSetEditor" )
> mainFrame.Show()
> app.MainLoop()

> If anyone can give any insight as to whats going on, I'd appreciate it.

You need to load the custom resource handler in your application code so
XRC knows how to construct an object of that type. Something like this:

    res\.InsertHandler\(xh\_floatspin\.FloatSpinCtrlXmlHandler\(\)\)

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Rob Falck wrote:

As I see it I have a few work-around options. I can either fall back
to TreeCtrl and make do without the columns, or I can not subclass the
TreeListCtrl and Bind events and methods to it after its created. I'd
love to understand the correct way to do this, though.

What does your subclass look like? Is it being called? Is it using 2-phase creation of the widget? Have you considered creating a new XmlResourceHandler for your derived class instead of using XRC's subclass attribute?

···

--
Robin Dunn
Software Craftsman

What does your subclass look like? Is it being called? Is it using
2-phase creation of the widget? Have you considered creating a new
XmlResourceHandler for your derived class instead of using XRC's
subclass attribute?

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Ah yes I forgot my subclass. I use two-stage creation. The class is
below. However, I think I found the problem. In the DoCreateResource
method of my handler I have the line

assert self.GetInstance() is None

This was raising an assertion error. Removing it seems to fix
everything, but I'm wondering why it was there. (I put it in since I
found it in the TreeListCtrlXmlHandler in wx.gizmos
http://websvn.osafoundation.org/filedetails.php?repname=wx&path=%2Fbranches%2Fwx-upstream%2FwxPython%2Fwx%2Ftools%2FXRCed%2Fplugins%2Fxh_gizmos.py&rev=199&sc=1)

Printing self before the assertion gives
<plotset_tree_ctrl.PlotSetTreeCtrl; proxy of <Swig Object of type
'wxPyTreeListCtrl *' at 0x1818d8a0> >

--------- plotset_tree_ctrl.py ------------------

# WxPython Modules
import wx
from wx.gizmos import TreeListCtrl, PreTreeListCtrl

# Local Modules

class PlotSetTreeCtrl(TreeListCtrl):
    """
    A tree list control to display a hierarchy of plot elements
    """

    def __init__(self):
        t=PreTreeListCtrl()
        self.PostCreate(t)
        self.Bind( wx.EVT_WINDOW_CREATE , self.OnCreate)

    def OnCreate(self,evt):
        self.Unbind ( wx.EVT_WINDOW_CREATE )
        wx.CallAfter(self.__PostInit)
        evt.Skip()
        return True

    def __PostInit(self):
        """
        Called after the window is created. Set up all the member
widget references here
        """
        pass

--------- end plotset_tree_ctrl.py ------------------

When I do not subclass TreeListCtrl, things appear on screen as they should, but attempting to drag the column widths of the TreeListCtrl result in Errors:

Python[61935] : CGAffineTransformInvert: singular matrix.

I still haven’t figured out why self.GetInstance() in DoCreateResource returns an instance of wxPyTreeListCtrl rather than None.

If anyone has a successful XRC-based example of in which TreeListCtrl is subclassed, I would be extremely grateful. I’ve exhausted my knowledge on this one :slight_smile:

···

On Wed, May 27, 2009 at 6:29 PM, Rob Falck robfalck@gmail.com wrote:

What does your subclass look like? Is it being called? Is it using

2-phase creation of the widget? Have you considered creating a new

XmlResourceHandler for your derived class instead of using XRC’s

subclass attribute?

Robin Dunn

Software Craftsmanhttp://wxPython.org

Ah yes I forgot my subclass. I use two-stage creation. The class is

below. However, I think I found the problem. In the DoCreateResource

method of my handler I have the line

assert self.GetInstance() is None

This was raising an assertion error. Removing it seems to fix

everything, but I’m wondering why it was there. (I put it in since I

found it in the TreeListCtrlXmlHandler in wx.gizmos

http://websvn.osafoundation.org/filedetails.php?repname=wx&path=%2Fbranches%2Fwx-upstream%2FwxPython%2Fwx%2Ftools%2FXRCed%2Fplugins%2Fxh_gizmos.py&rev=199&sc=1)

Printing self before the assertion gives

<plotset_tree_ctrl.PlotSetTreeCtrl; proxy of <Swig Object of type

‘wxPyTreeListCtrl *’ at 0x1818d8a0> >

--------- plotset_tree_ctrl.py ------------------

WxPython Modules

import wx

from wx.gizmos import TreeListCtrl, PreTreeListCtrl

Local Modules

class PlotSetTreeCtrl(TreeListCtrl):

"""

A tree list control to display a hierarchy of plot elements

"""



def __init__(self):

    t=PreTreeListCtrl()

    self.PostCreate(t)

    self.Bind( wx.EVT_WINDOW_CREATE , self.OnCreate)





def OnCreate(self,evt):

    self.Unbind ( wx.EVT_WINDOW_CREATE )

    wx.CallAfter(self.__PostInit)

    evt.Skip()

    return True



def __PostInit(self):

    """

    Called after the window is created.  Set up all the member

widget references here

    """

    pass

--------- end plotset_tree_ctrl.py ------------------

  • Rob Falck

Rob Falck wrote:

  When I do not subclass TreeListCtrl, things appear on screen as they should, but attempting to drag the column widths of the TreeListCtrl result in Errors:

Python[61935] <Error>: CGAffineTransformInvert: singular matrix.

I still haven't figured out why self.GetInstance() in DoCreateResource returns an instance of wxPyTreeListCtrl rather than None.

I haven't verified this in the code but my guess is that when the subclass is used then it has already called the subclass's __init__ by the time you get to that point in the handler, so you just need to call the Create.

···

--
Robin Dunn
Software Craftsman