Using XRC with Wizards

I've found the wiki page (http://wiki.wxpython.org/WizardFromXRC) that shows how to create a wizard with XRC. This works great, as long as all the pages are wx.wizard.wxWizardPageSimple instances. See the code after my sig. But once you make even one of them a wx.wizard. wxWizardPage, the code fails with the traceback:

Traceback (most recent call last):
   File "notsosimplewiz.py", line 45, in <module>
     wizard.RunWizard(page1)
   File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/wizard.py", line 365, in RunWizard
     return _wizard.Wizard_RunWizard(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "firstPage" failed at /BUILD/wxPython-src-2.8.4.0/src/generic/wizard.cpp(690) in RunWizard(): can't run empty wizard

  If you take the code below and change any one (or more) of the page objects from class="wxWizardPageSimple" to class="wxWizardPage", you'll get the traceback above.

  Can anyone point me to some docs for how to use non-simple wizard pages with XRC?

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
import wx, wx.xrc
import wx.wizard

definition = """\
<?xml version="1.0" encoding="UTF-8"?>
<resource version="2.3.0.1" xmlns="http://www.wxwidgets.org/wxxrc">
  <object class="wxWizard" name="SimpleWiz">
    <style>wxDEFAULT_DIALOG_STYLE|wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxCLOSE_BOX</style>
    <exstyle>wxWIZARD_EX_HELPBUTTON</exstyle>
    <title>SimpleWiz</title>
    <bitmap>wizard.png</bitmap>
    <object class="wxWizardPageSimple" name="pgFirst">
      <style>wxTAB_TRAVERSAL</style>
      <object class="wxStaticText" name="wxID_STATIC">
        <label>First Page</label>
      </object>
    </object>
    <object class="wxWizardPageSimple" name="pgSecond">
      <style>wxTAB_TRAVERSAL</style>
      <object class="wxStaticText" name="wxID_STATIC">
        <label>second page</label>
      </object>
    </object>
    <object class="wxWizardPageSimple" name="pgThird">
      <style>wxTAB_TRAVERSAL</style>
      <object class="wxStaticText" name="wxID_STATIC">
        <label>last page</label>
      </object>
    </object>
  </object>
</resource>"""

app = wx.App(0)

# Load the XRC resource
resource = wx.xrc.EmptyXmlResource()
resource.LoadFromString(definition)

wizard = resource.LoadObject(None, 'SimpleWiz', 'wxWizard')
page1 = wx.xrc.XRCCTRL(wizard, 'pgFirst')
wizard.RunWizard(page1)
wizard.Destroy()

app.MainLoop()

Correction: if you change the *first* page to a non-simple wizard page, you get that error. If you change the second or third, you get a dialog that says "wxWizardPage is abstract class, must be subclassed". How are you supposed to do that in a wizard using XRC?

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 23, 2007, at 4:04 PM, Ed Leafe wrote:

  If you take the code below and change any one (or more) of the page objects from class="wxWizardPageSimple" to class="wxWizardPage", you'll get the traceback above.

Ed Leafe wrote:

    I've found the wiki page (WizardFromXRC - wxPyWiki) that shows how to create a wizard with XRC. This works great, as long as all the pages are wx.wizard.wxWizardPageSimple instances. See the code after my sig. But once you make even one of them a wx.wizard. wxWizardPage, the code fails with the traceback:

Traceback (most recent call last):
  File "notsosimplewiz.py", line 45, in <module>
    wizard.RunWizard(page1)
  File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/wizard.py", line 365, in RunWizard
    return _wizard.Wizard_RunWizard(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "firstPage" failed at /BUILD/wxPython-src-2.8.4.0/src/generic/wizard.cpp(690) in RunWizard(): can't run empty wizard

    If you take the code below and change any one (or more) of the page objects from class="wxWizardPageSimple" to class="wxWizardPage", you'll get the traceback above.

    Can anyone point me to some docs for how to use non-simple wizard pages with XRC?

The C++ wxWizardPage class is abstract and can't be instantiated directly. You'll need to make your own subclass and either use the subclass attribute in the object tag or create a custom XmlResourceHandler for it.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

OK, thanks, but you're talking to an XRC noob here. Are there any examples I could see that do this? I've spent too many hours on trial-and-error to get this far; an actual example would speed things up for me.

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 23, 2007, at 5:42 PM, Robin Dunn wrote:

The C++ wxWizardPage class is abstract and can't be instantiated directly. You'll need to make your own subclass and either use the subclass attribute in the object tag or create a custom XmlResourceHandler for it.

Hi Ed,

The C++ wxWizardPage class is abstract and can't be instantiated directly. You'll need to make your own subclass and either use the subclass attribute in the object tag or create a custom XmlResourceHandler for it.

  OK, thanks, but you're talking to an XRC noob here. Are there any examples I could see that do this? I've spent too many hours on trial-and-error to get this far; an actual example would speed things up for me.

Run the wxPython demo and type XRC into the search box. I'm pretty sure there was a "resource subclass" demo in there. (The other demos might be helpful too. :slight_smile:

Regards,

Kevin

···

On May 23, 2007, at 3:20 PM, Ed Leafe wrote:

On May 23, 2007, at 5:42 PM, Robin Dunn wrote:

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Hi Ed,

Hi Ed,

The C++ wxWizardPage class is abstract and can't be instantiated directly. You'll need to make your own subclass and either use the subclass attribute in the object tag or create a custom XmlResourceHandler for it.

  OK, thanks, but you're talking to an XRC noob here. Are there any examples I could see that do this? I've spent too many hours on trial-and-error to get this far; an actual example would speed things up for me.

Run the wxPython demo and type XRC into the search box. I'm pretty sure there was a "resource subclass" demo in there. (The other demos might be helpful too. :slight_smile:

Sorry, you should do what I mean not what I say. :wink: The demo name is actually XmlResourceSubclass and the XmlResource demos are in the Window Layout section.

Regards,

Kevin

···

On May 23, 2007, at 3:27 PM, Kevin Ollivier wrote:

On May 23, 2007, at 3:20 PM, Ed Leafe wrote:

On May 23, 2007, at 5:42 PM, Robin Dunn wrote:

Regards,

Kevin

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

OK, thanks; that's a start. But I'm not getting how this works. It says that the subclass is specified as "moduleName.ClassName", and the example uses:

<object class="wxPanel" subclass="XmlResourceSubclass.MyCustomPanel" name="MyPanel">

with a class named 'MyCustomPanel' defined below the XRC. So far so good.

  Now I change the XRC subclass to read:

<object class="wxPanel" subclass="XmlResourceSubclass.DummyPanel" name="MyPanel">

...and I get the expected error:

"Error: Subclass 'XmlResourceSubclass.DummyPanel' not found for resource 'MyPanel', not subclassing!"

  So now I change the class to:

class DummyPanel(wx.Panel):

...and I still get the error? What am I missing here?

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 23, 2007, at 6:31 PM, Kevin Ollivier wrote:

  OK, thanks, but you're talking to an XRC noob here. Are there any examples I could see that do this? I've spent too many hours on trial-and-error to get this far; an actual example would speed things up for me.

Run the wxPython demo and type XRC into the search box. I'm pretty sure there was a "resource subclass" demo in there. (The other demos might be helpful too. :slight_smile:

Sorry, you should do what I mean not what I say. :wink: The demo name is actually XmlResourceSubclass and the XmlResource demos are in the Window Layout section.

Hi Ed,

  OK, thanks, but you're talking to an XRC noob here. Are there any examples I could see that do this? I've spent too many hours on trial-and-error to get this far; an actual example would speed things up for me.

Run the wxPython demo and type XRC into the search box. I'm pretty sure there was a "resource subclass" demo in there. (The other demos might be helpful too. :slight_smile:

Sorry, you should do what I mean not what I say. :wink: The demo name is actually XmlResourceSubclass and the XmlResource demos are in the Window Layout section.

  OK, thanks; that's a start. But I'm not getting how this works. It says that the subclass is specified as "moduleName.ClassName", and the example uses:

<object class="wxPanel" subclass="XmlResourceSubclass.MyCustomPanel" name="MyPanel">

with a class named 'MyCustomPanel' defined below the XRC. So far so good.

  Now I change the XRC subclass to read:

<object class="wxPanel" subclass="XmlResourceSubclass.DummyPanel" name="MyPanel">

...and I get the expected error:

"Error: Subclass 'XmlResourceSubclass.DummyPanel' not found for resource 'MyPanel', not subclassing!"

  So now I change the class to:

class DummyPanel(wx.Panel):

...and I still get the error? What am I missing here?

I think this is actually a limitation or bug of the "edit demo" feature in the wxPython demo. If you open the XmlResourceSubclass.py file in a text editor and make the changes there instead, then run it, it works as it's supposed to. So there's some module (re)loading magic that is not properly picking up the new class, or something like that.

Regards,

Kevin

···

On May 23, 2007, at 4:06 PM, Ed Leafe wrote:

On May 23, 2007, at 6:31 PM, Kevin Ollivier wrote:

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

That makes sense. So if I have a file named 'test.py' that contains the XRC for such a page, I should have something like this in test.py:

class MyCustomPage(wx.wizard.WizardPage):
  def GetNext(self):
    ...
  def GetPrev(self):
    ...

...and then in the XRC definition, I would have a line that reads:

<object class="wxWizardPage" name="NotASimplePage" subclass="test.MyCustomPage">

  If I do that, then I should be able to then call:

xrc.XRCCTRL(self, "NotASimplePage")

...and get a reference to that page? Does that sound right?

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 23, 2007, at 7:23 PM, Kevin Ollivier wrote:

I think this is actually a limitation or bug of the "edit demo" feature in the wxPython demo. If you open the XmlResourceSubclass.py file in a text editor and make the changes there instead, then run it, it works as it's supposed to. So there's some module (re)loading magic that is not properly picking up the new class, or something like that.

Kevin Ollivier wrote:

I think this is actually a limitation or bug of the "edit demo" feature in the wxPython demo. If you open the XmlResourceSubclass.py file in a text editor and make the changes there instead, then run it, it works as it's supposed to. So there's some module (re)loading magic that is not properly picking up the new class, or something like that.

Correct. The XmlSubclassFactory_Python class does a standard import using the module name specified, but the demo does some black magic tricery and compiles the source code of the module itself.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Ed Leafe wrote:

···

On May 23, 2007, at 7:23 PM, Kevin Ollivier wrote:

I think this is actually a limitation or bug of the "edit demo" feature in the wxPython demo. If you open the XmlResourceSubclass.py file in a text editor and make the changes there instead, then run it, it works as it's supposed to. So there's some module (re)loading magic that is not properly picking up the new class, or something like that.

    That makes sense. So if I have a file named 'test.py' that contains the XRC for such a page, I should have something like this in test.py:

class MyCustomPage(wx.wizard.WizardPage):
    def GetNext(self):
        ...
    def GetPrev(self):
        ...

...and then in the XRC definition, I would have a line that reads:

<object class="wxWizardPage" name="NotASimplePage" subclass="test.MyCustomPage">

    If I do that, then I should be able to then call:

xrc.XRCCTRL(self, "NotASimplePage")

...and get a reference to that page? Does that sound right?

Yes, except you'll want to derive your class from wx.wizard.PyWizardPage so you'll be using the one that knows how to reflect C++ virtual calls to the Python methods.

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Ed Leafe wrote:

    OK, thanks; that's a start. But I'm not getting how this works.

Aside from the wxPython demo, check out the wiki; I did a Text search for "xrc" and got the following results: Title Search: "xrc" - wxPyWiki -- you'll probably want to start with the ListCtrl subclassing.

···

--
Don Dwiggins
Advanced Publishing Technology

The output from calling gc.get_referents() did not change for self.iTunes or self.Events using the custom while loop or the MainLoop. The output from gc.get_referrers() did not change for self.iTunes, but for self.Events there was a considerably larger list, as suggested previously by the high ref count.

Here is the output from gc.get_referrers(self.Events) using the while loop:

[{'iTunes': <COMObject iTunes.Application>, 'Events': <win32com.client.COMEventClass instance at 0x01B5CF58>}]

Here is the output using MainLoop():

[{'_dispid_to_func_': {1: 'OnDatabaseChangedEvent', 2: 'OnPlayerPlayEvent', 3: 'OnPlayerStopEvent', 4: 'OnPlayerPlayingTrackChangedEvent', 5: 'OnUserInterfaceEnabledEvent', 6: 'OnCOMCallsDisabledEvent', 7: 'OnCOMCallsEnabledEvent', 8: 'OnQuittingEvent', 9: 'OnAboutToPromptUserToQuitEvent', 10: 'OnSoundVolumeChangedEvent'}, '_name_to_dispid_': {'onquittingevent': 8, 'oncomcallsenabledevent': 7, 'onuserinterfaceenabledevent': 5, 'ondatabasechangedevent': 1, 'onplayerplayingtrackchangedevent': 4, 'oncomcallsdisabledevent': 6, 'onsoundvolumechangedevent': 10, 'onplayerstopevent': 3, 'onabouttopromptusertoquitevent': 9, 'onplayerplayevent': 2}, '_query_interface_': <bound method COMEventClass._query_interface_ of <win32com.client.COMEventClass instance at 0x01B8FF08>>, '_dispid_to_put_': {}, '_dispid_to_get_': {}, '_com_interfaces_': , '_typeinfos_': None, '_obj_': <win32com.client.COMEventClass instance at 0x01B8FF08>}, <bound method COMEventClass._query_interface_ of <win32com.client.COMEventClass instance at 0x01B8FF08>>, {'_dispid_to_func_': {1: 'OnDatabaseChangedEvent', 2: 'OnPlayerPlayEvent', 3: 'OnPlayerStopEvent', 4: 'OnPlayerPlayingTrackChangedEvent', 5: 'OnUserInterfaceEnabledEvent', 6: 'OnCOMCallsDisabledEvent', 7: 'OnCOMCallsEnabledEvent', 8: 'OnQuittingEvent', 9: 'OnAboutToPromptUserToQuitEvent', 10: 'OnSoundVolumeChangedEvent'}, '_name_to_dispid_': {'onquittingevent': 8, 'oncomcallsenabledevent': 7, 'onuserinterfaceenabledevent': 5, 'ondatabasechangedevent': 1, 'onplayerplayingtrackchangedevent': 4, 'oncomcallsdisabledevent': 6, 'onsoundvolumechangedevent': 10, 'onplayerstopevent': 3, 'onabouttopromptusertoquitevent': 9, 'onplayerplayevent': 2}, '_query_interface_': <bound method COMEventClass._query_interface_ of <win32com.client.COMEventClass instance at 0x01B8FF08>>, '_dispid_to_put_': {}, '_dispid_to_get_': {}, '_com_interfaces_': , '_typeinfos_': None, '_obj_': <win32com.client.COMEventClass instance at 0x01B8FF08>}, <bound method COMEventClass._query_interface_ of <win32com.client.COMEventClass instance at 0x01B8FF08>>, {'_dispid_to_func_': {1: 'OnDatabaseChangedEvent', 2: 'OnPlayerPlayEvent', 3: 'OnPlayerStopEvent', 4: 'OnPlayerPlayingTrackChangedEvent', 5: 'OnUserInterfaceEnabledEvent', 6: 'OnCOMCallsDisabledEvent', 7: 'OnCOMCallsEnabledEvent', 8: 'OnQuittingEvent', 9: 'OnAboutToPromptUserToQuitEvent', 10: 'OnSoundVolumeChangedEvent'}, '_name_to_dispid_': {'onquittingevent': 8, 'oncomcallsenabledevent': 7, 'onuserinterfaceenabledevent': 5, 'ondatabasechangedevent': 1, 'onplayerplayingtrackchangedevent': 4, 'oncomcallsdisabledevent': 6, 'onsoundvolumechangedevent': 10, 'onplayerstopevent': 3, 'onabouttopromptusertoquitevent': 9, 'onplayerplayevent': 2}, '_query_interface_': <bound method COMEventClass._query_interface_ of <win32com.client.COMEventClass instance at 0x01B8FF08>>, '_dispid_to_put_': {}, '_dispid_to_get_': {}, '_com_interfaces_': , '_typeinfos_': None, '_obj_': <win32com.client.COMEventClass instance at 0x01B8FF08>}, <bound method COMEventClass._query_interface_ of <win32com.client.COMEventClass instance at 0x01B8FF08>>, {'iTunes': <COMObject iTunes.Application>, 'Events': <win32com.client.COMEventClass instance at 0x01B8FF08>}]

There doesn't seem to be anything wxPython specific in there, just COM classes. I'm still at a loss as to why these are retained using MainLoop() and not otherwise? Can anyone shed some light on this?

···

From: "Chris Mellon" <arkanes@gmail.com>

>Reply-To: wxPython-users@lists.wxwidgets.org
>To: wxPython-users@lists.wxwidgets.org
>Subject: Re: [wxPython-users] wxPython and reference counts
>Date: Wed, 23 May 2007 07:57:04 -0500
>
>On 5/23/07, Dave <davidn22@hotmail.com> wrote:
>>Hi,
>>
>>I have been attempting to solve a problem with the reference counts
>>of a COM object, preventing it from being freed. After more than a
>>year I've discovered it only occurs when in the wxPython
>>MainLoop().
>>I have included two files: main.py and itunes.py.
>>
>
><code snipped>
>
>You can use the get_referrers function in the gc module to find out
>who is holding a reference to an object.
>

OK, here's what I've done so far. I've changed the XRC to reflect the custom class, and then created the class definition in my test.py file. I've included the section of the XRC for the custom page, as well as the test.py code.

  When I try to run the design now, I get the following traceback:

Traceback (most recent call last):
   File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/xrc.py", line 733, in Create
     inst = klass()
TypeError: __init__() takes at least 2 arguments (1 given)

  I added some debugging print statements to the __init__(), CanHandle() and DoCreateResource() methods of the custom handler, and while I can confirm that the handler's __init__() is called, neither of the other two methods are ever called. What am I missing here?

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Relevant XRC:

<object class="wxWizardPage" name="pgCustom" subclass="test.CustomPage">
     <style>wxTAB_TRAVERSAL</style>
     <object class="wxGridSizer">
         <cols>1</cols>
         <rows>1</rows>
         <vgap>0</vgap>
         <hgap>0</hgap>
         <object class="sizeritem">
             <flag>wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL</flag>
             <border>5</border>
             <option>1</option>
             <object class="CustomPanel" name="pnlCustom">
                 <size>100,100</size>
                 <style>wxSIMPLE_BORDER</style>
             </object>
         </object>
     </object>
</object>

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#test.py

import wx
import wx.xrc as xrc
import wx.wizard as wiz

class CustomPage(wiz.PyWizardPage):
     def __init__(self, parent, *args, **kwargs):
         super(CustomPage, self).__init__(parent, *args, **kwargs)
     def GetNext(self):
         return None
     def GetPrev(self):
         return None

class CustomPageHandler(xrc.XmlResourceHandler):
     def __init__(self):
         xrc.XmlResourceHandler.__init__(self)
         self.AddWindowStyles()

     def CanHandle(self, node):
         self.clsName = node.GetProperties().Value
         return self.clsName == "CustomPage"

     def DoCreateResource(self):
         assert self.GetInstance() is None
         control = AskRegisterPage(self.GetParentAsWindow())
         self.SetupWindow(control)
         self.CreateChildren(control)
         return control

···

On May 23, 2007, at 8:44 PM, Robin Dunn wrote:

    That makes sense. So if I have a file named 'test.py' that contains the XRC for such a page, I should have something like this in test.py:
class MyCustomPage(wx.wizard.WizardPage):
    def GetNext(self):
        ...
    def GetPrev(self):
        ...
...and then in the XRC definition, I would have a line that reads:
<object class="wxWizardPage" name="NotASimplePage" subclass="test.MyCustomPage">
    If I do that, then I should be able to then call:
xrc.XRCCTRL(self, "NotASimplePage")
...and get a reference to that page? Does that sound right?

Yes, except you'll want to derive your class from wx.wizard.PyWizardPage so you'll be using the one that knows how to reflect C++ virtual calls to the Python methods.

Ed Leafe wrote:

    OK, here's what I've done so far. I've changed the XRC to reflect the custom class, and then created the class definition in my test.py file. I've included the section of the XRC for the custom page, as well as the test.py code.

    When I try to run the design now, I get the following traceback:

Traceback (most recent call last):
  File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/xrc.py", line 733, in Create
    inst = klass()
TypeError: __init__() takes at least 2 arguments (1 given)

    I added some debugging print statements to the __init__(), CanHandle() and DoCreateResource() methods of the custom handler, and while I can confirm that the handler's __init__() is called, neither of the other two methods are ever called. What am I missing here?

<object class="wxWizardPage" name="pgCustom" subclass="test.CustomPage">

[...]

#test.py

import wx
import wx.xrc as xrc
import wx.wizard as wiz

class CustomPage(wiz.PyWizardPage):
    def __init__(self, parent, *args, **kwargs):
        super(CustomPage, self).__init__(parent, *args, **kwargs)

This is the problem, you are calling the base class __init__ to create the instance, but you don't want to in this case. XRC relies on the 2-phase create model of the widget classes, so you need to create the C++ instance, but not create the widget (the base __init__ does both.) In C++ this would be done by calling the default (parameterless) constructor, in Python we do it by invoking the "Pre" factory. In this case you'll want to call

  p = wx.wizard.PrePyWizardPage()
  self.PostCreate(p)

The 2nd line moves the guts of the p instance over to self, so self becomes the proxy for the C++ instance created in the first line. Since the widget isn't fully created yet you can't do a whole lot with it. For this reason the samples bind EVT_WINDOW_CREATE which will be called after the widget is fully created. This happens after XRC calls the C++ wxWizardPage::Create method which will do further initialization and will also create the UI widget.

class CustomPageHandler(xrc.XmlResourceHandler):

Since you are using the subclass method there isn't any reason to have a XmlResourceHandler for it. This would only be needed if you wanted to handle custom tags within an <object> node, or if what you need doesn't fit very well in the subclass model for some other reason. To use a custom handler you would use the class name of the class supported by the handler, like this:

  <object class="CustomPage"> ...

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

OK, I understand better, and I'm no longer getting the "not subclassing" error message. Here's what I have now: same XRC:

<object class="wxWizardPage" name="NotASimplePage" subclass="test.MyCustomPage">

...and test.py now reads:

import wx
import wx.xrc as xrc
import wx.wizard as wiz
class MyCustomPage(wiz.PyWizardPage):
     def __init__(self, parent, *args, **kwargs):
         p = wx.wizard.PrePyWizardPage()
         self.PostCreate(p)

  I now get the following tracebacks:

Traceback (most recent call last):
   File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/xrc.py", line 733, in Create
     inst = klass()
TypeError: __init__() takes at least 2 arguments (1 given)

  I also cannot reference that object using xrc.XRCCTRL. If I add code in the wizard that contains this page to get the reference:

         self.CustomPage = xrc.XRCCTRL(self, "NotASimplePage")
  print self.CustomPage is None

...it prints True. Feels like I'm close, but not quite there yet. What else am I missing?

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 24, 2007, at 5:32 PM, Robin Dunn wrote:

#test.py
import wx
import wx.xrc as xrc
import wx.wizard as wiz
class CustomPage(wiz.PyWizardPage):
    def __init__(self, parent, *args, **kwargs):
        super(CustomPage, self).__init__(parent, *args, **kwargs)

This is the problem, you are calling the base class __init__ to create the instance, but you don't want to in this case. XRC relies on the 2-phase create model of the widget classes, so you need to create the C++ instance, but not create the widget (the base __init__ does both.) In C++ this would be done by calling the default (parameterless) constructor, in Python we do it by invoking the "Pre" factory. In this case you'll want to call

  p = wx.wizard.PrePyWizardPage()
  self.PostCreate(p)

The 2nd line moves the guts of the p instance over to self, so self becomes the proxy for the C++ instance created in the first line. Since the widget isn't fully created yet you can't do a whole lot with it. For this reason the samples bind EVT_WINDOW_CREATE which will be called after the widget is fully created. This happens after XRC calls the C++ wxWizardPage::Create method which will do further initialization and will also create the UI widget.

Ed Leafe wrote:

...and test.py now reads:

import wx
import wx.xrc as xrc
import wx.wizard as wiz
class MyCustomPage(wiz.PyWizardPage):
    def __init__(self, parent, *args, **kwargs):
        p = wx.wizard.PrePyWizardPage()
        self.PostCreate(p)

    I now get the following tracebacks:

Traceback (most recent call last):
  File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/xrc.py", line 733, in Create
    inst = klass()
TypeError: __init__() takes at least 2 arguments (1 given)

...

...it prints True. Feels like I'm close, but not quite there yet. What else am I missing?

Try taking the ", parent" out of the __init__ args; that may be why the error message says "takes at least 2 arguments".

···

--
Don Dwiggins
Advanced Publishing Technology

Bingo! Thanks; I was taking that from some boilerplate code. Now to move ahead until the next pitfall... :wink:

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 25, 2007, at 12:23 PM, Don Dwiggins wrote:

Try taking the ", parent" out of the __init__ args; that may be why the error message says "takes at least 2 arguments".

Actually, that seemed to be the last hurdle. I now have it working correctly.

  Thanks to you, Kevin and Robin for your help.

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com

···

On May 25, 2007, at 1:29 PM, Ed Leafe wrote:

Try taking the ", parent" out of the __init__ args; that may be why the error message says "takes at least 2 arguments".

  Bingo! Thanks; I was taking that from some boilerplate code. Now to move ahead until the next pitfall... :wink:

Ed Leafe wrote:

import wx
import wx.xrc as xrc
import wx.wizard as wiz
class MyCustomPage(wiz.PyWizardPage):
    def __init__(self, parent, *args, **kwargs):
        p = wx.wizard.PrePyWizardPage()
        self.PostCreate(p)

    I now get the following tracebacks:

Traceback (most recent call last):
  File "//Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode/wx/xrc.py", line 733, in Create
    inst = klass()
TypeError: __init__() takes at least 2 arguments (1 given)

As you've already found out the parent parameter is not needed. In fact the factory function that calls this doesn't pass any parameters at all to the __init__ so you can write it as just:

     def __init__(self):

    I also cannot reference that object using xrc.XRCCTRL. If I add code in the wizard that contains this page to get the reference:

        self.CustomPage = xrc.XRCCTRL(self, "NotASimplePage")
    print self.CustomPage is None

...it prints True.

Because the widget never got created because of the error above.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!