http://qs321.pair.com?node_id=578602

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

Esteemed monks,

In a Perl/Tk application I create a notebook, then a tab which I populate. One of the fields is a Tk::Entry which is to get a file name. But when the variable gets updated, the value shown in the Tk::Entry does not change on the screen.

Draw the notebook:
sub draw { my $self = shift; print "Notebook Page ", $self->{_nb}; my $notebook = $self->{_nb}->parent(); #$notebook->pageconfigure( 'page12', -raisecmd => sub { $self->_load +_configs } ); #notebook portion $self->{_subnb} = $self->{_nb}->NoteBook()->grid(); $self->{subnb_p1} = $self->{_subnb}->add( 'page1', -label => 'Prepar +e email message' ); $self->_draw_subnb_p1(); }
then populate it:
sub _draw_subnb_p1 { my $self = shift; # FRAME - top left side $self->{subnb_p1}->Label( -text => 'Email Subject', )->grid( $self->{subnb_p1}->Entry( -width => 50, -textvariable => \$::cini_global->{trickle}->{subject}, ), -padx => 5, -pady => 5, ); $self->{subnb_p1}->Label( -text => 'Email template', -width => '12', )->grid( $self->{subnb_p1}->Entry( -width => '50', -textvariable => \$::cini_global->{trickle}->{email_template_fil +e} ), $self->{subnb_p1}->Button( -text => 'Browse', -command => sub { $self->_getImportFile() }, ), $self->{_edemail_button} = $self->{subnb_p1}->Button( -text => 'Edit', -command => sub { $self->_edit_emailtemplate() }, ), -padx => 5, -pady => 5, ); my $top = $self->{subnb_p1}->Frame( -borderwidth => 2, -relief => 'r +aised' )->grid(); $top->Button( -text => 'Preview Email', -command => sub { $self->_preview_emailtemplate() }, )->grid( $top->Button( -text => 'Send Emails', -command => sub { $self->_send_emails() }, ), -padx => 5, -pady => 5, ); }
 $::cini_global is a global configuration hash whioch is populate using Config::IniHash

Now click on the button to change the file name and this gets called:

sub _getImportFile { my $self = shift; # Get the name of the file we are going to import my @types = ( [ "TMPL files", '.tmpl' ], [ "All Files", "*" ], ); $::cini_global->{trickle}->{email_template_file} = $self->{_nb}->get +OpenFile( -filetypes => \@types ); if ( $::cini_global->{trickle}->{email_template_file} ) { $self->{_edemail_button}->configure( -state => 'normal' ); } WriteINI( $::CONFIG_FILE, $::cini_global ); print Dumper $::cini_global; $self->{_mw}->update(); }
You will see as soon as I get the file name I write the config hash back to disk - just in case. I can see the file change when I look at it, but despite the fact that $::cini_global->{trickle}->{email_template_file} has changed the display does not change! Am I doing something stupid here? Or is there a bug somewhere??

jdtoronto

Replies are listed 'Best First'.
Re: Tk::Entry not updating when textvariable changes.
by GrandFather (Saint) on Oct 16, 2006 at 22:35 UTC

    How about crunching this down to a short 10 line sample that reproduces the problem, that doesn't depend on a whole pile of context that we can't see and doesn't require external file access? <grummpymode>There's about a 99% chance that you will find the problem yourself in the process, but that's the price you pay for focusing on the issue rather than getting us to trawl through the code for you.</grummpymode>


    DWIM is Perl's answer to Gödel
      Yeah, I know. I was up to my armpits in this problem and had to rush out the door for a meeting and some other stuff and wanted to get it out there to hopefully get some clues by the time I got back! Pretty presumptuous of me I know.

      Penitently, jdtoronto

Re: Tk::Entry not updating when textvariable changes.
by shmem (Chancellor) on Oct 16, 2006 at 22:57 UTC
    Bear with me, I have the same difficulties as you to grok your code ;-)
    -textvariable => \$::cini_global->{trickle}->{email_template_file}

    Is this a reference? is $cini_global a hash reference? Is the value that falls out the dereferencing chain a reference?

    $::cini_global->{trickle}->{email_template_file} = $self->{_nb}->getOp +enFile(-filetypes => \@types );
    is $self->{_nb}->getOpenFile(-filetypes => \@types ) returning a reference? Are you passing a value or a reference via that assignment?

    Having these questions answered, the solution to the problem may be simple ;-)

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      I'm suspicious of Config::IniHash myself... I'm operating under the assumption that the $cini_global is a hashRef, and I know that getOpenFile returns a scalar -- in this case a selected filename. Here's a shortened example:

      use Tk; use strict; $::cini_global = { trickle => { email_template_file => "nothing" }}; my $mw = MainWindow->new; $mw->Entry( -width => 40, -textvariable => \$::cini_global->{trickle}->{email_template_file} )->pack(qw/-expand 1 -fill x/); $mw->Button( -text => "Change", -command => sub { $::cini_global->{trickle}->{email_template_file} = $mw->getOpenFile(); })->pack; MainLoop;

      I suspect there's something else going on outside of the shown code. Perhaps Config::IniHash creates something different than what it appears

      Update: It would seem that Config::IniHash does some pretty interesting things under the hood and isn't exactly what it seems. I haven't looked at all the code, but my guess is that the two times you use it, the internal references are different. I've added a second example that shows how I'd work around it if I had to use Config::IniHash, which I'm not certain that I would.

      <crotchety voice>Config::IniHash seems a bit too clever for its own good to me</crotchety voice> Still, its code makes for pretty interesting reading ;-)

      Example 2 : In the second example I was able to reprodce the reported problem. The code shows how I worked around it.

      config file, containing:

      [trickle] email_template_file=nothing

      Script with workaround:

      use strict; use Config::IniHash; use Data::Dumper; use Tk; $::cini_global = ReadINI 'config'; my $ref = $::cini_global->{trickle}->{email_template_file}; my $mw = MainWindow->new; $mw->Entry( -width => 40, -textvariable => \$ref )->pack(qw/-expand 1 -fill x/); $mw->Button( -text => "Change", -command => sub { $ref = $mw->getOpenFile(); $::cini_global->{trickle}{email_template_file} = $ref; })->pack; MainLoop;
      Rob
Re: Tk::Entry not updating when textvariable changes.
by runrig (Abbot) on Oct 17, 2006 at 00:04 UTC
    Is the global hash ref populated before or after the screen widgets are created?
Re: Tk::Entry not updating when textvariable changes.
by mikasue (Friar) on Oct 17, 2006 at 00:14 UTC
    I can see the file change when I look at it, but despite the fact that $::cini_global->{trickle}->{email_template_file} has changed

    From your statement the file is getting updated the display just isn't.

    The problem is not with textvariable. I had this same problem. I had to redraw the screen after another call to the import file. So I would suggest after you make the change reload the import file and then redraw the screen.