From: Mattia B. <mb...@ds...> - 2002-09-05 17:33:06
|
> Something I've found annoying is that some classes are > implemented as scalar references. Say I want to > subclass Wx::MenuBar. Because it is a scalar reference > instead of the normal hash reference, I can't do this: <snip> > I think since wxWindows philosophy/API is very object-oriented, > that perhaps (unless there is a technical reason forbidding it) > those classes should be hash refs. Well, wxPerl classes are arbitrarily divided in "subclassable" and "not subclassable"; Subclassable: 1a. ->new returns an hash ref 1b. wxPerl always returns the original hash ref from wxWindows methods (f.e. from ->GetChildren or ->GetParent) Not subclassable: 2a. -> new returns a scalar ref 2b. wxPerl creates a new scalar ref every time it needs to return such an object from wxWindows methods Having 1b requires a small but nonzero amount of work, so I try not to have it without necessity (BTW subclassing wxMenuBar is unusual, why do you need it? just curious); I could have 1a and 2b, but that would be confusing ---- my $a = Wx::MenuBar->new(...); $frame->SetMenuBar( $a ); my $b = $frame->GetMenuBar; # $a is an hash ref, $b is a scalar ref, OR another hash ref, # different from the first one ---- I can move wxMenuBar (or any other class) to subclassable (or to not subclassable) it just requires some small work. Regards Mattia |
From: Scott L. <sla...@th...> - 2002-09-06 06:25:14
|
On Thu, 5 Sep 2002, Mattia Barbon wrote: > (BTW subclassing wxMenuBar is unusual, why do you need it? > just curious); I just did it to separate the menubar code in its own module. For example, to do a minimal application with a menubar to trigger a dialog, I would have 1) a main script, 2) MyApp.pm, 3) MyFrame.pm, 4) MyMenuBar.pm, 5) MyDialog.pm, 6) MyPanel.pm, with Frame the parent of MenuBar and Dialog, and Dialog the parent of Panel. Maybe it's a little awkward if I have a dialog triggered by a menu event, though, because the dialog has the Frame for its parent and I end up doing things like this from the MenuBar subclass no strict 'refs'; EVT_MENU($parent, '...', \&{ref($parent) . 'OnMenuDialog'}); (so MyFrame isn't hardcoded, though still we have OnMenuDialog hardcoded..) to pass it back to the Frame class anyway. So maybe this is why it's unusual to subclass MenuBar. Anyway, MenuBar is not the only scalar class I tried to subclass. I also tried some dialogs like TextEntryDialog and SingleChoiceDialog. You might again say it's unusual to subclass these, as they are small and specific, but I like to treat all the dialog as objects when I do something like $d = MyDialog->new(); $d->Destroy(); then inside of MyDialog I did something like (it's from memory, hopefully you get the idea though) sub new { ... if ($self->ShowModal() == wxOK) { $self->{textfield} = $self->GetStringSelection(); ... } return $self; } Basically I mean I treat the Dialog as an object which had some attributes set by the user (as a CGI programmer, I think of the form submit button and $q->param() to get the CGI form values), then I use $d from above like if ($d->{textfield} =~ /whatever.../) { .... } and so on. (Really I use Class::Accessor::Fast and Class::Fields modules to do easy AUTOLOAD of private and public attributes, so instead of $self->{textfield} = ... I have $self->textfield(...) and access simply with $self->textfield - so from the perspective the dialog parent it seems as if $d->textfield is an accessor method of an object.) > I can move wxMenuBar (or any other class) to subclassable (or > to not subclassable) it just requires some small work. Speaking of this.. what is the trick? I'm trying to understand what makes the objects be either a HASH or SCALAR reference. I grepped for 'bless' in the source code, and I think the only relevant case is function wxPli_make_object in ./cpp/helpers.cpp. It creates a new HASH, but how is a SCALAR object created? I looked at XS/Menu.xs for MenuBar which is a SCALAR, and its `new' is barebones, just translates the C++ directly. On the other hand, XS/Frame.xs, XS/TreeCtrl.xs, XS/Panel.xs, those have RETVAL = new wxPliSOMETHING where SOMETHING is Frame, TreeCtrl, Panel, etc. I search around a little -- panel.h, helpers.h -- find these WXPLI_DEFAULT_CONSTRUCTOR and so on all call wxPli_make_object. Aha. But still, what about the SCALAR ones? There is a comment in cpp/helpers.cpp of the wxPli_sv_2_object function in wxHashModule class that says "get 'this' pointer from a blessed scalar/hash reference". I grepped wxPli_sv_2_object and found it in ./typemap, but it was in the INPUT section. In the TYPEMAP section, I found both wxMenuBar and wxFrame are O_WXOBJECT, and in the OUTPUT section, O_WXOBJECT uses wxPli_object_2_sv. It's hurting my mind now. |
From: Mattia B. <mb...@ds...> - 2002-09-06 16:39:32
|
> On Thu, 5 Sep 2002, Mattia Barbon wrote: > > (BTW subclassing wxMenuBar is unusual, why do you need it? > > just curious); > > I just did it to separate the menubar code in its own module. > For example, to do a minimal application with a menubar to > trigger a dialog, I would have 1) a main script, 2) MyApp.pm, > 3) MyFrame.pm, 4) MyMenuBar.pm, 5) MyDialog.pm, 6) MyPanel.pm, > with Frame the parent of MenuBar and Dialog, and Dialog the > parent of Panel. Maybe it's a little awkward if I have a dialog > triggered by a menu event, though, because the dialog has the > Frame for its parent and I end up doing things like this from > the MenuBar subclass > > no strict 'refs'; > EVT_MENU($parent, '...', \&{ref($parent) . 'OnMenuDialog'}); $parent->can( 'OnMenuDialog' ) looks cleaner to me, BTW > (so MyFrame isn't hardcoded, though still we have OnMenuDialog > hardcoded..) > > to pass it back to the Frame class anyway. So maybe this is > why it's unusual to subclass MenuBar. Exactly, basically, once you start putting data in the menubar, you realize that it would be much easier to put it in the frame directly. > Anyway, MenuBar is not the only scalar class I tried to > subclass. I also tried some dialogs like TextEntryDialog > and SingleChoiceDialog. You might again say it's unusual > to subclass these, as they are small and specific, but I like > to treat all the dialog as objects when I do something like > > $d = MyDialog->new(); > $d->Destroy(); > > then inside of MyDialog I did something like (it's from memory, > hopefully you get the idea though) > > sub new { > ... > > if ($self->ShowModal() == wxOK) { > $self->{textfield} = $self->GetStringSelection(); > ... > } > return $self; > } > > Basically I mean I treat the Dialog as an object which had some > attributes set by the user (as a CGI programmer, I think of the > form submit button and $q->param() to get the CGI form values), > then I use $d from above like > > if ($d->{textfield} =~ /whatever.../) { > .... > } > > and so on. (Really I use Class::Accessor::Fast and Class::Fields > modules to do easy AUTOLOAD of private and public attributes, > so instead of $self->{textfield} = ... I have $self->textfield(...) > and access simply with $self->textfield - so from the perspective > the dialog parent it seems as if $d->textfield is an accessor > method of an object.) Well, de gustibus disputandum non est... > > I can move wxMenuBar (or any other class) to subclassable (or > > to not subclassable) it just requires some small work. > > Speaking of this.. what is the trick? > > I'm trying to understand what makes the objects be > either a HASH or SCALAR reference. I grepped for 'bless' > in the source code, and I think the only relevant case is > function wxPli_make_object in ./cpp/helpers.cpp. > It creates a new HASH, but how is a SCALAR object created? it is never created, see below. > I looked at XS/Menu.xs for MenuBar which is a SCALAR, > and its `new' is barebones, just translates the C++ directly. > On the other hand, XS/Frame.xs, XS/TreeCtrl.xs, XS/Panel.xs, > those have RETVAL = new wxPliSOMETHING where SOMETHING is Frame, > TreeCtrl, Panel, etc. I search around a little -- panel.h, > helpers.h -- find these WXPLI_DEFAULT_CONSTRUCTOR and so on > all call wxPli_make_object. Aha. But still, what about the > SCALAR ones? > > There is a comment in cpp/helpers.cpp of the wxPli_sv_2_object > function in wxHashModule class that says "get 'this' pointer > from a blessed scalar/hash reference". I grepped wxPli_sv_2_object > and found it in ./typemap, but it was in the INPUT section. In the > TYPEMAP section, I found both wxMenuBar and wxFrame are O_WXOBJECT, > and in the OUTPUT section, O_WXOBJECT uses wxPli_object_2_sv. > It's hurting my mind now. :-) create a class like this (this is for wxListCtrl): class wxPliListCtrl:public wxListCtrl { WXPLI_DECLARE_DYNAMIC_CLASS( wxPliListCtrl ); WXPLI_DECLARE_SELFREF(); public: WXPLI_DEFAULT_CONSTRUCTOR( wxPliListCtrl, "Wx::ListCtrl", TRUE ); WXPLI_CONSTRUCTOR_7( wxPliListCtrl, "Wx::ListCtrl", TRUE, wxWindow*, wxWindowID, const wxPoint&, const wxSize&, long, const wxValidator&, const wxString& ); }; For wxMenuBar (which hasn't a default ctor, just 1-arg and 3-arg ones), you should use CONSTRUCTOR_1 and CONSTRUCTOR_3 (they should be added to helpers.h, it's a matter of cut'n'paste'n'modify. There are handy macros (WXPLI_DECLARE_CLASS_X) that do this in the case of a default ctor + X-args ctor, BTW. Now, why does this work? WXPLI_CONSTRUCTOR_X calls wxPli_make_object (create the hashref) and stores it in the m_self attribute of the class (declared by WXPLI_DECLARE_SELFREF() or WXPLI_DECLARE_V_CBACK()); in addition WXPLI_DECLARE_DYNAMIC_CLASS( wxPliListCtrl ); adds the class information for this class to the RTTI system used by wxWindows. Now, when wxPli_object_2_sv comes to decide how to convert the wxObject to a Perl-thing, it gets the RTTI class information and sees that the class name starts with wxPl, it assumes it is a wxPerl thing, and uses the additional information stored in the wxPliClassInfo object to locate the m_self memeber, get the hashref stored here, and return it. If that fails, it uses sv_setref_pv to create a new SCALAR reference and returns it. If you post a list of classes that you need to be HASH-ified, I think I could do that for 0.12 . Regards Mattia |
From: Scott L. <sla...@th...> - 2002-09-07 18:32:52
|
On Fri, 6 Sep 2002, Mattia Barbon wrote: > Scott Lanning wrote: > > Frame for its parent and I end up doing things like this from > > the MenuBar subclass > > > > no strict 'refs'; > > EVT_MENU($parent, '...', \&{ref($parent) . 'OnMenuDialog'}); > $parent->can( 'OnMenuDialog' ) looks cleaner to me, BTW I didn't know `can' returns the CODE ref. Thanks! > the wxPliClassInfo object to locate the m_self memeber, get the > hashref stored here, and return it. If that fails, it uses > sv_setref_pv to create a new SCALAR reference and returns it. Thanks for the explanation. Hopefully I get more familiar with it and can help making some wrapper. > If you post a list of classes that you need to be HASH-ified, > I think I could do that for 0.12 . I was thinking just in terms of making the library better in general; I would feel selfish to request these things for myself. If you don't care either way, then: Wx::MenuBar, Wx::SingleChoiceDialog, Wx::TextEntryDialog; but these are only ones that I stumbled across so far as I learn the library. I'm still learning wxPerl and might not be using the correct approach. Even now I might change my mind to a different approach; for example, I just found XRC which looks very nice, and maybe then I am less likely to subclass these objects. In my mind, _all_ classes that can be subclassed should ideally be hashes, but I only mean it to be an idea to consider. |