http://www.perlmonks.org?node_id=1022462

HelenCr has asked for the wisdom of the Perl Monks concerning the following question:

Dear esteemed PerlMonks

I am trying to develop GUI-based application, (moving from Win32::GUI to wxPerl/wxWidgets). I find it pretty difficult, the documentation and tutorials are very sketchy.

Trying to implement a (very simple) short list control, I am trying to port a Python example.

Here is the Python code, taken from: http://www.blog.pythonlibrary.org/2011/01/04/wxpython-wx-listctrl-tips-and-tricks/

import wx ###################################################################### +## class MyForm(wx.Frame): #----------------------------------------------------------------- +----- def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutoria +l") # Add a panel so it looks the correct on all platforms panel = wx.Panel(self, wx.ID_ANY) self.index = 0 self.list_ctrl = wx.ListCtrl(panel, size=(-1,100), style=wx.LC_REPORT |wx.BORDER_SUNKEN ) self.list_ctrl.InsertColumn(0, 'Subject') self.list_ctrl.InsertColumn(1, 'Due') self.list_ctrl.InsertColumn(2, 'Location', width=125) btn = wx.Button(panel, label="Add Line") btn.Bind(wx.EVT_BUTTON, self.add_line) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5) sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5) panel.SetSizer(sizer) #----------------------------------------------------------------- +----- def add_line(self, event): line = "Line %s" % self.index self.list_ctrl.InsertStringItem(self.index, line) self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010") self.list_ctrl.SetStringItem(self.index, 2, "USA") self.index += 1 #--------------------------------------------------------------------- +- # Run the program if __name__ == "__main__": app = wx.App(False) frame = MyForm() frame.Show() app.MainLoop()

and here is the ported Perl program:

# wxPerl list control test 7 3 2013. Based on Tutorial 8 # Taken from: http://wxperl.sourceforge.net/tutorial/tutorial4.html # and http://www.blog.pythonlibrary.org/2011/01/04/wxpython-wx-listctr +l-tips-and-tricks/ use strict; use warnings; use warnings qw< FATAL utf8 >; use Wx; use Encode; use 5.014; use utf8; use autodie; use Carp; use Carp qw {cluck}; use Carp::Always; use Win32::Console; use English '-no_match_vars'; package MyApp; use base 'Wx::App'; use Wx qw{ wxLC_REPORT wxBORDER_SUNKEN wxVERTICAL wxALL wxEXPAND wxCEN +TER}; sub OnInit { my $frame = MyForm->new; $frame->Show( 1 ); } # end package MyApp; package MyForm; use base 'Wx::Frame'; use Wx qw{ wxLC_REPORT wxBORDER_SUNKEN wxVERTICAL wxALL wxEXPAND wxCEN +TER}; # import the event registration function use Wx::Event qw(EVT_BUTTON); our ($idx, $list_ctrl); sub new { my $ref = shift; my $self = $ref->SUPER::new( undef, # parent window -1, # ID -1 means any 'List Control Tutorial', # title [-1, -1], # default position [400, 300], # size ); # Add a panel so it looks correct on all platforms my $panel = Wx::Panel->new( $self, # parent window -1, # ID ); $idx = 0; $list_ctrl = Wx::ListCtrl-> new ($panel, -1, # ID 'Report', # lab +el [20,30], # posi +tion [-1,100], # siz +e &Wx::wxLC_REPORT | + &Wx::wxBORDER_SUNKEN, # window style ); $list_ctrl->InsertColumn( 0, 'Subject' ); $list_ctrl->InsertColumn( 0, 'Due' ); $list_ctrl->InsertColumn( 0, 'Location' ); my $btn = Wx::Button->new( $panel, # parent window -1, # ID 'Add Line', # label [-1, -1], # default position [-1, -1], # default size ); EVT_BUTTON( $self, $btn, \&add_line ); my $sizer = Wx::BoxSizer->new(&Wx::wxVERTICAL); $sizer->Add($list_ctrl, 0, &Wx::wxALL| &Wx::wxEXPAND, 5); $sizer->Add($btn, 0, &Wx::wxALL | &Wx::wxCENTER, 5); $panel->SetSizer($sizer); } # end sub new sub add_line { # my $event; my ( $self, $event ) = @_; my $line = "Line $idx"; $list_ctrl->InsertStringItem($idx, $line); $list_ctrl->SetStringItem($idx, 1, '01/19/2010'); $list_ctrl->InsertStringItem($idx, 2, 'USA'); $idx += 1; } # end sub add_line 1; # end package MyForm; package main; my $app = MyApp->new; $app->MainLoop; 1;

When running the Perl program, it issues the cryptic error:

variable is not of type Wx::Point at Wx List Control test PerlO.pl lin +e 52 MyForm::new('MyForm') called at Wx List Control test PerlO.pl line 25 MyApp::OnInit('MyApp=HASH(0x2407e64)') called at F:/Win7programs/Dwimp +erl/perl/site/lib/Wx/App.pm line 36 eval {...} called at F:/Win7programs/Dwimperl/perl/site/lib/Wx/App.pm +line 36 Wx::App::new('MyApp') called at F:/Win7programs/Dwimperl/perl/site/lib +/Wx/App.pm line 36 Wx::App::new('MyApp') called at Wx List Control test PerlO.pl line 88

(the program name is: "Wx List Control test PerlO.pl").

Line 52 is the statement:

$list_ctrl = Wx::ListCtrl-> new ($panel, -1, # ID 'Report', # lab +el [20,30], # posi +tion [-1,100], # siz +e &Wx::wxLC_REPORT | + &Wx::wxBORDER_SUNKEN, # window style );

(System: DWIMPerl 5.14.2 on Windows 7).

Your help will be appreciated - this is holding up the development.

Many TIA - Helen

Replies are listed 'Best First'.
Re: wxPerl fails with a cryptic message: "variable is not of type Wx::Point"
by kcott (Archbishop) on Mar 08, 2013 at 20:49 UTC

    G'day Helen,

    I'm not a Wx user; however, the documentation seems to indicate that the value you've used for position (i.e. [20,30]) needs to be a Wx::Point instance. See Update below for an issue with the argument list.

    I agree that the documentation is not optimal. Here's the links I followed to glean the above information:

    I also found Wx::Perl::ListCtrl which you may be interested in: its description claims it provides "a sane api for Wx::ListCtrl".

    Update: Your Wx::ListCtrl->new() call contains an additional argument ('Report',    # label) which is throwing position, and subsequent arguments, off by one. Accordingly, the error message you received refers to 'Report' not being a Wx::Point.

    -- Ken

Re: wxPerl fails with a cryptic message: "variable is not of type Wx::Point"
by stefbv (Curate) on Mar 08, 2013 at 21:39 UTC

    That error was the easiest part..., I made a few changes and fixes and this is the result, to keep the development going :)

    package MyForm; use strict; use warnings; use Wx qw[:everything]; # easy when testing use Wx::Event qw(EVT_BUTTON); use base 'Wx::Frame'; use Wx::Perl::ListCtrl; sub new { my $class = shift; my $self = $class->SUPER::new( undef, # parent window -1, # ID -1 means any 'List Control Tutorial', # title [ -1, -1 ], # default position [ 400, 300 ], # size ); # Add a panel so it looks correct on all platforms my $panel = Wx::Panel->new( $self, # parent window -1, # ID ); my $idx = 0; $self->{list_ctrl} = Wx::Perl::ListCtrl->new( $panel, -1, # ID #'Report', # label [ 20, 30 ], # position [ -1, 100 ], # size wxLC_REPORT | wxBORDER_SUNKEN, # window style ); $self->{list_ctrl}->InsertColumn( 0, 'Subject' ); $self->{list_ctrl}->InsertColumn( 0, 'Due' ); $self->{list_ctrl}->InsertColumn( 0, 'Location' ); my $btn = Wx::Button->new( $panel, # parent window -1, # ID 'Add Line', # label [ -1, -1 ], # default position [ -1, -1 ], # default size ); EVT_BUTTON( $self, $btn, sub { $self->add_line($idx); $idx++; } ); my $sizer = Wx::BoxSizer->new(&Wx::wxVERTICAL); $sizer->Add( $self->{list_ctrl}, 0, wxALL | wxEXPAND, 5 ); $sizer->Add( $btn, 0, wxALL | wxCENTER, 5 ); $panel->SetSizer($sizer); return $self; } # end sub new sub add_line { my ( $self, $idx ) = @_; my $line = "Line $idx"; $self->{list_ctrl}->InsertStringItem( $idx, $line ); return; } # end sub add_line package MyApp; use strict; use warnings; use base 'Wx::App'; sub OnInit { my $frame = MyForm->new; $frame->Show(1); } package main; my $app = MyApp->new; $app->MainLoop;

    Regards, Stefan

      Thank you, Stefan, for the thorough answer, and the investment of time and energy. Your post is really helpful. The program, the way you tweaked it, works fine.
      And many thanks to kcott and the other Anonymous Monks who pitched in and responded.

      Following up: Stefan and Monks, I'll be thankful to you if you could help me with the following questions (apologizing beforehand if some of them are quasi-newbie's):

      1. If you examine the Python code example, http://www.blog.pythonlibrary.org/2011/01/04/wxpython-wx-listctrl-tips-and-tricks/, see the lines:
        self.index = 0 self.list_ctrl = wx.ListCtrl(panel, size=(-1,100), style=wx.LC_REPORT |wx.BORDER_SUNKEN )
        Then for self.index = 0 we port it to Perl by declaring a new variable: my $idx =0; So, to port the second line, why not declare a new variable: my $list_ctrl; ?
      2. and what kind of object is $self->{list_ctrl} ? Is it a reference to an anonymous hash? and where is list_ctrl now defined?
      3. When do you use  &Wx::wxLC_SOMETHING, and when just: wxLC_SOMETHING? I notice that you haven't changed it everywhere, but left in some of the subroutine calls?
      4. I notice that you did not include the lines:
        $self->{list_ctrl}->SetStringItem($idx, 1, '01/19/2010'); $self->{list_ctrl}->SetStringItem($idx, 2, 'USA');
        If I do include them, compilation fails with: Can't locate object method "SetStringItem" via package "Wx::Perl::ListCtrl" at Wx List Control test v2.pl line 69.
        How to overcome this? In other words, how do you modify/ insert strings in a ListCTRL line?
      5. Looking ahead, the next necessary step for me, is to "tie" a database table to the Wx List Control, so that when the user scrolls at the GUI window, the application keeps retrieving database table lines (records) and displays them at the window.
        Is there a way to "tie" an RDBMS table to a Wx List Control?

      Thanks again for your thorough help - Helen

        I'm not very good at explaining things, but I'l try, wxLC_xREPORT, wxBORDER_SUNKEN,... are constant integers defined in the Wx package but not imported by default (for example wxLC_xREPORT == 32). After import you can use the short form. If a constant is not imported you can prepend the class name like this: Wx::wxLC_xREPORT. (I'm not sure about the '&').

        I did not change everywhere because it was almost midnight and missed it, no other reason :)

        The sole purpose of the $idx variable is numbering in the label. It uses a closure , see Closure on Closures

        The $list_ctrl variable, in your version of the example, is the reference to the list control object. It is assigned once at the creation of the widget object. This object has methods to add columns and rows to the list, so we need to save it somewhere so we can use it later. One method is to use a hash reference to save it so i can refer to the list object later from other subs.

        Here is how to add data to columns, also using the shortcut form from Anonymous Monk - (thanks!)

        package MyForm; use strict; use warnings; use Wx qw[:everything]; # easy when testing use Wx::Event qw(EVT_BUTTON); use base 'Wx::Frame'; use Wx::Perl::ListCtrl; sub new { my $class = shift; my $self = $class->SUPER::new( undef, # parent window -1, # ID -1 means any 'List Control Tutorial', # title [ -1, -1 ], # default position [ 400, 300 ], # size ); # Add a panel so it looks correct on all platforms my $panel = Wx::Panel->new( $self, # parent window -1, # ID ); my $idx = 0; $self->{list_ctrl} = Wx::Perl::ListCtrl->new( $panel, -1, # ID #'Report', # label [ 20, 30 ], # position [ -1, 100 ], # size wxLC_REPORT | wxBORDER_SUNKEN, # window style ); print " wxLC_REPORT is ", wxLC_REPORT,"\n"; print " wxBORDER_SUNKEN is ", wxBORDER_SUNKEN,"\n"; $self->{list_ctrl}->InsertColumn( 0, 'Subject' ); $self->{list_ctrl}->InsertColumn( 0, 'Due' ); $self->{list_ctrl}->InsertColumn( 0, 'Location' ); my $btn = Wx::Button->new( $panel, # parent window -1, # ID 'Add Line', # label [ -1, -1 ], # default position [ -1, -1 ], # default size ); EVT_BUTTON( $self, $btn, sub { $self->add_line($idx); $idx++; } ); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add( $self->{list_ctrl}, 0, wxALL | wxEXPAND, 5 ); $sizer->Add( $btn, 0, wxALL | wxCENTER, 5 ); $panel->SetSizer($sizer); return $self; } sub add_line { my ($self, $item) = @_; #$item = 0; # unexpected behaviour print " Inserting item $item\n"; my ($col, $text) = (0, 'text'); $self->{list_ctrl}->InsertStringItem( $item, 'dummy' ); $self->{list_ctrl}->SetItemText( $item, $col , "$text.$item.0" ); $self->{list_ctrl}->SetItemText( $item, $col+1, "$text.$item.1" ); $self->{list_ctrl}->SetItemText( $item, $col+2, "$text.$item.2" ); return; } #-- my $app = Wx::SimpleApp->new; my $frame = MyForm->new; $frame->Show(1); $app->MainLoop;

        What is interesting and unespected for me, is that item can be 0 and still adds rows, I was expectig to overwrite the first item.

        Stefan

        Update: Replaced '32' with 'wxLC_REPORT'. I was trying to show that wxLC_REPORT is just a constant, but the result was a wrong example. Also removed 'Wx::' from the other flag.

        1 .. 2

        yes, self is an object, a hash based object, it a reference to a hash, and yes those references are usually anonymous (outside of the constructor) :)

        index and list_ctrl are attributes of the object -- its object oriented programming -- if they weren't attributes then you couldn't create 20 MyForm's and still have it work, you'd have to create an @index and @list_ctrl -- this is not good for a "Class" ( a module for making object)

        See perlootut, Modern Perl

        When do you use &Wx::wxLC_SOMETHING, and when just: wxLC_SOMETHING?

        Whenever you want :)

        There is a cost to importing constants into a package, and Wx has a lot of them (1mb worth or more), but they all already live in the Wx:: namespace so you can call them Wx::blahblah() and conserve memory -- padre does this, cause 100 subclasses * 1mb = 100mb, not good :)

        OTOH, I suppose the same memory saving effect could be accomplished with less typing with use namespace::clean;

        In any case, whether you type it, or you use a oneliner to fixup your constants, or use WxEXPORTS to cherrypick your exports, or whatever, do what hurts the least and fits your process

        Can't locate object method "SetStringItem" ... How to overcome this

        Read what you're reading closer, read the actual documentation, http://docs.wxwidgets.org/2.8/wx_wxlistctrl.html#wxlistctrlsetitem

        wxPython note: In place of a single overloaded method name, wxPython implements the following methods: SetItem(item) Sets information about the given wxListItem. SetStringItem(index, col, label, imageId) Sets a string or image at a given location.

        So taking a page out of my tutorial

        $ perl -MWx -le " Wx::ListCtrl->new->SetItem" unable to resolve overloaded method for Wx::ListCtrl::SetItem at -e li +ne 1. $ perl -MWx -le " Wx::ListCtrl->new->SetItem( 1 .. 10 )" Usage: Wx::ListCtrl::SetItemString(THIS, index, col, label, image = -1 +) at -e line 1.

        Is there a way to "tie" an RDBMS table to a Wx List Control?

        Yes, its called programming :P

      You could even write

      my $app = Wx::SimpleApp->new; my $frame = MyForm->new; $frame->Show(1); $app->MainLoop;
      skips the extra subclassing :)
Re: wxPerl fails with a cryptic message: "variable is not of type Wx::Point"
by Anonymous Monk on Mar 08, 2013 at 20:55 UTC
Re: wxPerl fails with a cryptic message: "variable is not of type Wx::Point"
by jmlynesjr (Deacon) on Mar 09, 2013 at 03:55 UTC

    HelenCr:

    I agree that the documentation is pretty sparse which is why I ported the wxBook examples, see the GitHub reference above. I use the pdf document "wxWidgets 2.8.10: A Portable C++ and Python GUI Toolkit" by Julian Smart, Robert Roebling, Vadim Zeitlin, Robin Dunn, et al February 2009. It's for C++ with wxPerl and Python notes sprinkled in where the usage varies. The 2381 pages is a lot to digest, but it does get easier to use as you get the hang of how things translate. Most of what I have found so far demonstrates individual widget usage. I am having trouble finding examples of a more complete application. I understand that this may be difficult as real applications will probably contain modules that any given user may not have installed.

    There has been a lot of recent discussion on the mailing list - wxperl-users@perl.org - about writing a wxPerlBook to parallel the wxBook. This is also a good place to post questions. There is also some activity on StackOverflow.

    There is a new resource you should check out that collects several resources together - http://www.wxperl.it.

    Then there's always http://www.wxwidgets.org and http://wiki.wxwidgets.org, but these also have the problem of being C++ documentation which will require interpretation.

    James

    There's never enough time to do it right, but always enough time to do it over...

      James (jmlynesjr): Thank you for your positive answer.

      I have downloaded the Smart, Roebling et Al. document you mentioned. It refers to samples/examples, but does not contain them. Can you refer me to the examples?

      Referring to the dearth and scarcity of documentation on wxPerl, I can't seem to find good wxPerl documentation on wxListCTRL, and especially on tying a database table to a list control - while there is lots of Python documentation.

      It's interesting to note this emotional expression of frustration: http://osdir.com/ml/lang.perl.wxperl/2006-06/msg00010.html Quote:

      Trying to search for solutions in the WxPerl arena is like trying to find water in a desert, docs and good examples are slim to none.
      Unquote

      Many thanks again - Helen

        There is a new site: http://www.wxperl.it/, maintained by Mark Dootson that looks promising as a reference regarding WxPerl documentation.

        Helen:

        I have seen the references to the samples/examples, but I haven't found them either. The wxBook references a CDROM that didn't come with my book. The wxPerl Demo package is pretty good, but the wrapper code added to allow the mass of widgets to be included into a unified application can add to the confusion.

        In addition, the questions come in multiple layers. Once you get past the "Hello World" and individual widget examples, there's finding information on the style and structure of complete applications which is maybe not just a wxPerl issue.

        Just post specific questions here and to the mailing list and see what comes up. Please note when you cross post to multiple forums.:)

        Update1: See the file "TheBridge" on the GitHub repository to see where I have gotten so far in documenting the next steps. This is a draft that I hope to keep adding to.

        James

        There's never enough time to do it right, but always enough time to do it over...

        AM:

        Not coming from a C++ background, it took a few light-bulb moments and much reading and rereading before the C++ documentation started making sense. It gets easier to use with experience.

        James

        There's never enough time to do it right, but always enough time to do it over...

Re: wxPerl fails with a cryptic message: "variable is not of type Wx::Point"
by Anonymous Monk on Mar 08, 2013 at 20:44 UTC