Dear Mark Thank you. This indeed works. I learned something new. $panel2->TransferDataToWindow; # does work. It's magic. This means that the Wx::Panel package has a TransferDataToWindow method.
But, When I go, according to your suggestion: $panel2->InitDialog; It bumps with: "Can't locate object method "InitDialog" via package "Wx::Panel" at" ... etc. Should I add something? A couple of thoughts: 1. Why are validators implemented using cloning? Why is it necessary? I did a little experiment, and went (in the TC_test frame constructor): #... $self->{TCtrl_v} = $TCtrl_v; #... and in the OnClose sub: if( not $self->{$TCtrl_v}->TransferFromWindow ) { # ... and this works, too; in other words, if I copy the validator pointer to another variable (manually) and use it later, it works. Why is that? (Doesn't this make validator cloning unnecessary?) 2. It's interesting to note that the need ( a must) to call GetValidator is not mentioned in the (scarce) documentation (neither in the general wxWidgets or wxPython one). Many thanks for your help and support Helen On Sun, Jun 16, 2013 at 5:45 PM, Mark Dootson <mark.doot...@znix.com> wrote: > Hi, > > The code example demonstrates the specific issue you are having perfectly > well. > > When you assign a validator to a Window, a copy of the validator object is > created. This is why you need a Clone method. > > After you assign TCtrl_v as the validator for your Window, the instance is > cloned and the cloned instance is used to validate Window input / output. > > The TCtrl_v instance itself is never used to validate. > > So, to fix your particular error: > > replace > > if( not $TCtrl_v->TransferFromWindow ) { > with > if( not $TCtrl->GetValidator->**TransferFromWindow ) { > > and > replace > $TCtrl_v->TransferToWindow; > with > $TCtrl->GetValidator->**TransferToWindow; > > > For general use of validators I'll be adding a tutorial to the wxPerl site > in the next couple of days - however the key points are > > Create your containers (e.g. Wx::Panel instances) with the extra style > wxWS_EX_VALIDATE_RECURSIVELY > > To transfer data to window, call $panel->TransferDataToWindow on the top > level panel. > > To transfer data from window call > if( $panel->Validate ) { > $panel->**TransferDataFromWindow; > } > on the top level panel. > > Wx::Dialog does much of this automatically. You might also like to > experiment with $panel->InitDialog. > > Your exact implementation will depend on your data and it's source. > For example, your data must be available when you call > TransferDataToWindow. > > Hope it helps. > > Regards > > Mark > > > > On 16/06/2013 12:03, Mary Guardi wrote: > >> =begin comment >> Dear Mark >> >> Thank you for your prompt reply. This program I'm running is not small >> (~580 lines), and I didn't want to clog the forum. >> I any case, I went through the program now, and sifted out the >> irrelevant parts ( irrelevant for this question) (even so it's ~140 >> lines). Here it is - it's runnable. >> >> Please note the following: the program contains 4 packages, the relevant >> ones are "TC_test" and "MyValidator". >> The program logic (trivially simple) goes like this: package "main" >> calls package "MyForm", which displays a frame. Clicking the button >> "select_btn" calls sub "prep_query", which calls package "TC_test". >> package "TC_test" creates a text control called "$TCtrl", to which >> "TCtrl_v": a "MyValidator" validator is attached. >> >> Like I said in the OP, before leaving sub "new TC_test" it tries to >> executes: >> $TCtrl_v->TransferToWindow; >> and breaks saying: "Can't call method "SetValue" on an undefined value >> at ... .pl line 150." >> >> Many TIA >> >> Helen >> >> =end comment >> =cut >> >> use strict; >> use warnings; >> use Wx; >> >> package MyForm;# ------------------------------**------- package >> MyForm:: >> use strict; >> use warnings; >> use 5.014; >> use parent -norequire, 'Wx::Frame'; >> use Wx::Event qw(EVT_BUTTON); >> use Wx qw[:everything]; >> >> sub new { #1 ---------------------------new MyForm:: >> my $class = shift; >> my $self = $class->SUPER::new( undef,-1, 'Frame class: MyForm', >> wxDefaultPosition, wxDefaultSize ); >> my $panel = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize); >> >> # ... >> my $select_btn = Wx::Button->new( $panel, -1, 'DB Select query', >> wxDefaultPosition, wxDefaultSize); >> EVT_BUTTON( $self, $select_btn, >> sub { #3 >> prep_query(); >> } #3 end sub >> );# end EVT_BUTTON continue_btn call >> # ... >> my $sizer = Wx::BoxSizer->new(wxVERTICAL); >> my $sizer1_h = Wx::BoxSizer->new(**wxHORIZONTAL); >> $sizer1_h -> Add ( $select_btn, 0, wxALL, 5 ); >> # ... >> $sizer->Add( $sizer1_h, 1, wxEXPAND); >> $panel->SetSizer($sizer); >> $panel->Fit; >> return $self; >> sub prep_query {#2preparing query >> >> my $select_query_frame = TC_test->new; >> $select_query_frame->Show(1); >> }#2 end sub prep_query >> }#1 end sub new MyForm:: >> # ... >> 1; >> # end package MyForm >> >> package TC_test;# ------------------------------**----- package >> TC_test:: >> use strict; >> use warnings; >> use Wx; >> use 5.014; >> use parent -norequire, 'Wx::Frame'; >> use Wx::Event qw(EVT_BUTTON EVT_CLOSE); >> use Wx qw( wxDefaultPosition wxDefaultSize wxTE_PROCESS_ENTER); >> # ... >> sub new {# ------------------------------**-------- new TC_test:: >> my $class = shift; >> # ... >> my $self = $class->SUPER::new( undef,-1, 'Frame class: TC_test', >> >> wxDefaultPosition, wxDefaultSize); >> my $panel2 = Wx::Panel->new($self,-1, >> wxDefaultPosition, wxDefaultSize); >> # ... >> my $TCtrl = Wx::TextCtrl->new($panel2, -1, q{}, >> wxDefaultPosition, [20,-1], wxTE_PROCESS_ENTER); >> my $TCtrl_v = MyValidator->new( \$main::text_value); >> $TCtrl->SetValidator( $TCtrl_v); >> my $sizer_main = Wx::FlexGridSizer->new(7,7,5,**5); >> # ... >> $sizer_main->Add($TCtrl, 0); >> # ... >> $sizer_main->Fit($self); >> $sizer_main->SetSizeHints($**self); >> # ... >> EVT_CLOSE( $self, >> sub {#2 >> if( not $TCtrl_v->Validate ) { >> Wx::LogMessage( "Data is invalid" ); >> return; >> } >> if( not $TCtrl_v->TransferFromWindow ) { >> Wx::LogMessage( "Error in data transfer" ); >> return; >> } >> $self->Wx::Window::Destroy; >> }#2 end sub of EVT_CLOSE >> );#1end EVT_CLOSE call >> >> $TCtrl_v->TransferToWindow; >> # here it breaks saying: "Can't call method "SetValue" on an undefined >> value at ... etc...". >> return $self; >> }#1 end sub new TC_test:: >> 1; >> # end package TC_test#------------------- end package TC_test >> >> >> package MyValidator;#----------------- package MyValidator >> # helped by: >> http://articles.mongueurs.net/**magazines/linuxmag71.html<http://articles.mongueurs.net/magazines/linuxmag71.html> >> use strict; >> use Wx qw(wxOK wxICON_ERROR); >> use parent -norequire, 'Wx::PlValidator';# Classe de base >> sub new {# Constructeur >> my $class = shift; >> my $var_r = shift;# Ref de la variable associe >> my $this = $class->SUPER::new; >> $this->{var_r} = $var_r;# Pour consultation ultrieure >> return $this; >> } # end sub new >> sub Clone {# Indispensable pour les Validators car ils sont clon?s en >> interne >> my $this = shift; >> my $new = MyValidator->new( # Transmet la reference a la variable >> associe >> $this->{var_r} ); >> return $new; >> } # end sub Clone >> sub Validate {# Appel?e par Wx::Dialog->Validate >> my( $this, $dialog ) = @_; >> my $V_var = $this->GetWindow->GetValue;# La methode GetWindow >> retourne le widget concerne >> # Verification personnalisee >> if ($V_var !~ /^[A-Z ]+$/) {# ici uniquement des caracteres >> alphabetiques majuscules et l'espace >> Wx::MessageBox( "Erreur: $V_var n'est pas une valeur admissible.", # >> Affichage d'un Pop-up informatif >> "Error", wxOK|wxICON_ERROR, undef ); >> return 0;# Signale notre probleme au Dialog >> } >> 1;# Signale que tout va bien >> } # end sub Validate >> sub TransferFromWindow {# Copie le contenu du controle dans la variable >> associe >> my $this = shift; >> ${$this->{var_r}} = $this->GetWindow->GetValue; >> 1;# Signale que tout va bien >> } # end sub TransferFromWindow >> sub TransferToWindow {# Copie le contenu de la variable associ?e dans le >> controle >> my $this = shift; >> $this->GetWindow->SetValue( ${$this->{var_r}} ); >> 1;# Signale que tout va bien >> } # end sub TransferToWindow >> 1; >> # end package MyValidator;#------- end package MyValidator >> >> package main;# ------------------------------**---------------- package >> main:: >> use strict; >> use warnings; >> # ... >> # déclaration et initialisation de la variable interne associée au >> Validator >> $main::text_value = 'FOO BAR'; >> my $app = Wx::SimpleApp->new; >> my $frame = MyForm->new; >> $frame->Show(1); >> $app->MainLoop; >> 1; >> >> >> >> On Sun, Jun 16, 2013 at 4:48 AM, Mark Dootson <mark.doot...@znix.com >> <mailto:mark.doot...@znix.com>**> wrote: >> >> Hi, >> >> >> On 15/06/2013 22:23, Helen Craigman wrote: >> >> Dear esteemed WxPerl experts and users: >> I have been trying to incorprate a validator on a TextCtrl >> widget, using >> PlValidator (following this: >> >> ...... >> >> This gives the error: "Can't call method "SetValue" on an >> undefined >> value at..." etc. >> >> >> As far as my own usage is concerned, classes derived from >> Wx::PlValidator work perfectly. >> >> For me to either help you to get your Wx::PlValidator derived class >> working, or identify some bug in Wx::PlValidator, you would have to >> post some code that can be run and demonstrates the failure you are >> experiencing. >> >> The code snippet you have posted doesn't show a validator being >> assigned to a Wx::TextCtrl - so it cannot be an accurate >> representation of the code that fails for you. You clearly have >> worked out how a Validator should work if you get as far as the >> error reported, and you probably just need a simple adjustment in >> your code to make it work. But without seeing the actual failing >> code I have no clue what might be causing the failure. >> >> I feel that I am always giving negative answers to the Wx questions >> you ask on this list and Perl Mongers - and I feel really bad about >> this as you have clearly figured out 99% of what is required yourself. >> >> I can't help if you don't post some actual code - or even a snippet >> taken from actual code. I'd guess you are missing a Clone method in >> your derived class, but who knows. The code you posted can't be the >> code you are running. >> >> Regards >> >> Mark >> >> >> >> >> >> >