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

Everyone, Problem was fixed by doing configure on @wtpercentbox and changing my @wtpercentbox to our @wtpercentbox
First off, let me thank the entire community for helping and instructing me on a project on which I am working. Every question I have asked so far has recieved a prompt and excellent reply. I am having another problem, however now, and would love some input. My code is getting longer and longer, but I will try to keep it as simple as possible for this question. Let me set up the situation: I have created multiple sets of entry widgets, the first one requires user input, the second one should display the results of the calculations performed on those first entry widgets. I have all the entry values going into an array, and all of the calculated values going into an array as well. I also have created a status bar as a way of error checking so I can print various things to it to see where I stand. Here is my situation: When I click my "Calculate" button, all of the widgets update on my page except the entry widgets which are supposed to display the result. I currently have the status bar printing the results array, and it is correct, but my entry widgets will not update.
Here is the code that creates the entry widgets (the one that won't update is $wtpercentbox$i:
my $i = 0; for my $chems (sort keys %density) { my $row = $i+2; $frame3->Label(-text=>$chems)->grid(-row=>$row,-column=>1); $densitybox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, -te +xtvariable => \$density[$i], -justify => "center")->grid(-row=>$row,- +column=>2); $concentrationbox[$i] = $frame3->Entry(-bg=>'grey', -width => +5, -textvariable => \$concentration[$i], -justify => "center")->grid( +-row=>$row,-column=>3); $ratiobox[$i] = $frame3->Entry(-bg=>'white', -width => 5, -tex +tvariable => \$ratio[$i], -justify => "center")->grid(-row=>$row,-col +umn=>4); $wtpercentbox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, - +textvariable => \$wtPercent[$i], -justify => "center")->grid(-row=>$r +ow,-column=>5); $i++; }
Here is the code that is called to do the calculations and upate @wtPercent:
sub RATIOCALC { our ($mOrv, @ratio, @density, @concentration, %chemname, @wtPercen +t, $statustext, @wtpercentbox); my (@wtPureAmt, @residualDI); if (defined($mOrv)){ $statustext = "Calculating..."; if ($mOrv eq "V"){ for (my $i = 0; $i <= $#ratio; $i++){ $ratio[$i] = $ratio[$i] * $density[$i]; $mOrv = "M"; }; }; for (my $j = 0; $j <= $#ratio; $j++){ $wtPureAmt[$j] = $ratio[$j] * $concentration[$j]; }; for (my $k = 0; $k <= $#ratio; $k++){ $residualDI[$k] = $ratio[$k] * (1 - $concentration[$k]); }; my $totalmass = sum(@ratio); my $diIndex = $chemname{'DI'}; if ($totalmass != 0){@wtPercent = map{$_ / $totalmass}@wtPureA +mt}else{$statustext = "You need to give me numbers!"}; if ($wtPureAmt[$diIndex] == 0) { $wtPercent[$diIndex] = sum(@residualDI) / $totalmass; } else { $wtPercent[$diIndex] = (sum(@residualDI) + $wtPureAmt[$diI +ndex]) / $totalmass; } $statustext = "(@wtPercent)"; }else{ $statustext = "You need to select weight or volume ratio!" };
Here is all of my code in progress:
#!/usr/bin/env perl -w require Tk; use Tk; use Tk::Font; use Tk::Text; use Tk::ROText; use English; use strict; use warnings; our %density = ( DI => "1.0", HF => "1.16", NH4OH => "0.9", H202 => "1.11", HCl => "1.18", H2SO4 => "1.84", Citric => "1", NH4F => "1.01", TMAH => "1.0", Nitric => "1.415", Acetic => "1.05", Phosphoric => "1.7", IPA => "0.79" ); our %concentration =( DI => "1.0", HF => "0.49", NH4OH => "0.29", H202 => "0.3", HCl => "0.37", H2SO4 => ".98", Citric => "0.5", NH4F => "0.4", TMAH => "0.25", Nitric => "0.7", Acetic => "0.8", Phosphoric => "0.85", IPA => "1.0" ); my $mw = MainWindow->new; $mw -> title("BathCalc Selection"); $mw -> geometry("+200+200"); #Setting frames in main window. my $menuframe = $mw -> Frame( -relief => "groove", -borderwidth => 2 )->pack( -side => "top", -fill => "x", ); my $topframe = $mw -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, -pady => 5 ); my $midframe = $mw -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, ); my $botframe = $mw -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, -pady => 5 ); #command to make a file menubutton my $file_mw = $menuframe -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_mw -> command( -label => "Exit", -command => sub{$mw -> destroy} ); my $help_mw = $menuframe -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_mw -> command( -label => "About", -command => sub{&ABOUT}); #setting up selections as to where to go next my $rb; my $r1=$midframe->Radiobutton( -text=>"Calculate Amount of Material to Pour a Bath", -value=>"1", -variable=>\$rb ) -> pack(side => 'top', -anchor => 'w'); my $r2=$midframe->Radiobutton( -text=>"Convert Chemical Ratio to Mass Percent", -value=>"2", -variable=>\$rb ) -> pack(side => 'top', -anchor => 'w'); my $r3=$midframe->Radiobutton( -text=>"Display Assumptions", -value=>"3", -variable=>\$rb ) -> pack(side => 'top', -anchor => 'w'); my $text1 = $topframe->Label ( -text => "Selection:", -font => '{times new roman} 14' ) -> pack(side => 'top', -anchor => 'w'); my $actionButton = $botframe -> Button( -text => "Go", -command => \&CHOOSE ) -> pack(-side => 'left', padx => '50', pady => '20'); my $exitButton = $botframe -> Button( -text => "Quit", -command => sub{exit} ) -> pack(-side => 'right', padx => '50', pady => '20'); MainLoop (); sub CHOOSE { if ($rb == 1) { &MAKE_BATH; } elsif ($rb == 2) { &RATIO; } elsif ($rb == 3) { &ASSUME; } } sub MAKE_BATH #This subroutine will generate a new window that will +require user input to calculate volumes #required to pour up a bath of known size and concentr +ation. The default concentration and #density will be displayed and allow users to change i +f they need to do so. { my $mb = MainWindow -> new; $mb -> title("Bath Pour Up"); $mb -> geometry("+200+200"); #this frame is going to be the menu bar. my $frame1 = $mb -> Frame( -relief => "groove", -borderwidth => 3 )->pack( -side => "top", -fill => "x" ); my $file_mb = $frame1 -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_mb -> command( -label => "Exit", -command => sub{$mb -> destroy}); my $help_mb = $frame1 -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_mb -> command( -label => "About", -command => sub{&ABOUT} #The next section sets up all of the frames I will need, many, many fr +ames... ); my $midhold = $mb -> Frame()->pack( -side => "top", -fill => "x", -padx => 3 ); my $frame2 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); our $frame3 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); my $calcVolframe = $mb -> Frame( -borderwidth => 3 )->pack( -side => "top", -fill => 'x', ); my $frame12 = $mb -> Frame( #this is the bottom frame with the st +atus button in it. -relief => "raised", -borderwidth => 3 )->pack( -side => "bottom", -fill => 'x', ); our $totalvolume; my $voltext = $calcVolframe -> Entry( -textvariable => \$totalvolume, -width => 5 ) -> pack( -side => 'right', -padx => 36); my $volLbl = $calcVolframe ->Label( -text => "Bath Volume (L):" ) -> pack(-side=>'right'); #------------------------------------------------------------ #Calculate Button Below #------------------------------------------------------------ my $calcButton = $calcVolframe -> Button( -text => "Calculate", -command => \&VOLCALC ) -> pack(-side => 'left', padx => '50', pady => '10'); #------------------------------------------------------------ #Calculate Button Above #------------------------------------------------------------ our $i = 0; our(@wtpercent, @wtpercentbox, @concentration, $isSolv, @volume, @ +density); my (@concentrationbox, @densitybox, @volumebox); #need to make sure that concentration and density are always in th +e same order. my $j = 0; foreach (sort keys(%concentration)){ $concentration[$j] = $concentration{$_}; $density[$j] = $density{$_}; $j++; }; my $headingOne = $frame3 ->Label( -text => "Solvent", -relief => "raised" ) -> grid (-column=>0, -row => 1); my $headingTwo = $frame3 ->Label( -relief => "raised", -text => "Chemical Name" ) -> grid (-column=>1, -row => 1); my $headingThree = $frame3 ->Label( -relief => "raised", -text => "Density (g/mL)" ) -> grid (-column=>2, -row => 1); my $headingFour = $frame3 ->Label( -text => "Concentration (%)", -relief => "raised" ) -> grid (-column=>3, -row => 1); my $headingFive = $frame3 ->Label( -text => "Wt %", -relief => "raised", -width => 5 ) -> grid (-column=>4, -row => 1); my $headingSix = $frame3 ->Label( -text => "Calculated Volume (L)", -relief => "raised" ) -> grid (-column=>5, -row => 1); for my $x (sort keys %density) { my $row = $i+2; $frame3->Radiobutton( -value=>$i, -variable => \$isSolv, -command=>[\&colorme, $i])->grid(-row=>$row,-column=>0); $frame3->Label(-text=>$x)->grid(-row=>$row,-column=>1); $densitybox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, -te +xtvariable => \$density[$i])->grid(-row=>$row,-column=>2); $concentrationbox[$i] = $frame3->Entry(-bg=>'grey', -width => +5, -textvariable => \$concentration[$i])->grid(-row=>$row,-column=>3) +; $wtpercentbox[$i] = $frame3->Entry(-bg=>'white', -width => 5, +-textvariable => \$wtpercent[$i])->grid(-row=>$row,-column=>4); $volumebox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, -tex +tvariable => \$volume[$i])->grid(-row=>$row,-column=>5); $i++; } our $statustext = "Please enter desired weight percent and sol +vent."; my $statuslabel = $frame12 -> Label( -text => "Status: " ) -> pack(-side => "left"); my $status =$frame12 -> Entry( -textvariable => \$statustext, -foreground => 'red', -width => 60 ) -> pack(-side => "left"); } sub RATIO #This subroutine will generate a new window that will requ +ire user input to calculate weight percents #based on supplied ratios { my $rt = MainWindow -> new; $rt -> title("Ratio to Weight Percent"); $rt -> geometry("+200+200"); #this frame is going to be the menu bar. my $frame1 = $rt -> Frame( -relief => "groove", -borderwidth => 3 )->pack( -side => "top", -fill => "x" ); my $file_rt = $frame1 -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_rt -> command( -label => "Exit", -command => sub{$rt -> destroy}); my $help_rt = $frame1 -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_rt -> command( -label => "About", -command => sub{&ABOUT} #The next section sets up all of the frames I will need, many, many fr +ames... ); my $midhold = $rt -> Frame()->pack( -side => "top", -fill => "x", -padx => 3 ); my $frame2 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); my $frame3 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); my $calcVolframe = $rt -> Frame( -borderwidth => 3 )->pack( -side => "top", -fill => 'x', ); my $frame12 = $rt -> Frame( #this is the bottom frame with the st +atus button in it. -relief => "raised", -borderwidth => 3 )->pack( -side => "bottom", -fill => 'x', ); my $VolButton = $calcVolframe -> Button( -text => "Bath Volume >>", -command => \&RATIOSUP ) -> pack(-side => 'right', padx => '5', pady => '5'); our $mOrv; my $mOrvbutton = $calcVolframe -> Radiobutton( -variable => \$mOrv, -value => "M", -width => 5 ) -> pack( -side => 'right'); my $massText = $calcVolframe -> Label( -text => "Mass Ratio ", -padx => 2) -> pack(-side => "right"); my $mOrvbutton2 = $calcVolframe -> Radiobutton( -variable => \$mOrv, -value => "V", -width => 5 ) -> pack( -side => 'right'); my $volLbl = $calcVolframe ->Label( -text => "Volume Ratio:" ) -> pack(-side=>'right'); #------------------------------------------------------------ #Calculate Button Below #------------------------------------------------------------ my $calcButton = $calcVolframe -> Button( -text => "Calculate", -command => \&RATIOCALC ) -> pack(-side => 'left', padx => '50', pady => '10'); #------------------------------------------------------------ #Calculate Button Above #------------------------------------------------------------ our(@ratio, @ratiobox, @concentration, @wtPercent, @density, %chem +name); my (@concentrationbox, @densitybox, @wtpercentbox); #need to make sure that concentration and density are always in th +e same order. my $j = 0; foreach (sort keys(%concentration)){ $concentration[$j] = $concentration{$_}; $density[$j] = $density{$_}; $chemname{$_} = $j; $ratio[$j] = 0; $wtPercent[$j] = 0; $j++; }; my $headingTwo = $frame3 ->Label( -relief => "raised", -text => "Chemical Name" ) -> grid (-column=>1, -row => 1, -padx => 3, -pady =>2); my $headingThree = $frame3 ->Label( -relief => "raised", -text => "Density (g/mL)" ) -> grid (-column=>2, -row => 1, -padx => 3, -pady =>2); my $headingFour = $frame3 ->Label( -text => "Concentration", -relief => "raised" ) -> grid (-column=>3, -row => 1, -padx => 3, -pady =>2); + my $headingFive = $frame3 ->Label( -text => "Ratio", -relief => "raised", -width => 5 ) -> grid (-column=>4, -row => 1, -padx => 3, -pady =>2); my $headingSix = $frame3 ->Label( -text => "Calculated Wt Percent", -relief => "raised" ) -> grid (-column=>5, -row => 1, -padx => 3, -pady =>2); my $i = 0; for my $chems (sort keys %density) { my $row = $i+2; $frame3->Label(-text=>$chems)->grid(-row=>$row,-column=>1); $densitybox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, -te +xtvariable => \$density[$i], -justify => "center")->grid(-row=>$row,- +column=>2); $concentrationbox[$i] = $frame3->Entry(-bg=>'grey', -width => +5, -textvariable => \$concentration[$i], -justify => "center")->grid( +-row=>$row,-column=>3); $ratiobox[$i] = $frame3->Entry(-bg=>'white', -width => 5, -tex +tvariable => \$ratio[$i], -justify => "center")->grid(-row=>$row,-col +umn=>4); $wtpercentbox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, - +textvariable => \$wtPercent[$i], -justify => "center")->grid(-row=>$r +ow,-column=>5); $i++; } our $statustext = "Please enter desired ratio and whether wt o +r vol percent."; my $statuslabel = $frame12 -> Label( -text => "Status: " ) -> pack(-side => "left"); my $status =$frame12 -> Entry( -textvariable => \$statustext, -foreground => 'red', -width => 60 ) -> pack(-side => "left"); } ###################################################################### +###### ###################################################################### +###### # This sub is responsible for calculating the wt percents of the che +micals # supplied in the ratio screen # MAIN -> RT -> RATIOCALC ###################################################################### +##### sub VOLCALC { our $isSolv; if (defined($isSolv)){ my @chemname = (sort keys(our %density)); my $solventname = $chemname[$isSolv]; our $statustext = "Calculating"; }else{ our $statustext = "You need to select a solvent" }; } ###################################################################### +###### ###################################################################### +###### # This sub is responsible for calculating the wt percents of the che +micals # supplied in the ratio screen # MAIN -> RT -> RATIOCALC ###################################################################### +##### sub RATIOCALC { our ($mOrv, @ratio, @density, @concentration, %chemname, @wtPercen +t, $statustext, @wtpercentbox); my (@wtPureAmt, @residualDI); if (defined($mOrv)){ $statustext = "Calculating..."; if ($mOrv eq "V"){ for (my $i = 0; $i <= $#ratio; $i++){ $ratio[$i] = $ratio[$i] * $density[$i]; $mOrv = "M"; }; }; for (my $j = 0; $j <= $#ratio; $j++){ $wtPureAmt[$j] = $ratio[$j] * $concentration[$j]; }; for (my $k = 0; $k <= $#ratio; $k++){ $residualDI[$k] = $ratio[$k] * (1 - $concentration[$k]); }; my $totalmass = sum(@ratio); my $diIndex = $chemname{'DI'}; if ($totalmass != 0){@wtPercent = map{$_ / $totalmass}@wtPureA +mt}else{$statustext = "You need to give me numbers!"}; if ($wtPureAmt[$diIndex] == 0) { $wtPercent[$diIndex] = sum(@residualDI) / $totalmass; } else { $wtPercent[$diIndex] = (sum(@residualDI) + $wtPureAmt[$diI +ndex]) / $totalmass; } $statustext = "(@wtPercent)"; }else{ $statustext = "You need to select weight or volume ratio!" }; map{$_->configure(-textvariable=>\$wtPercent[2])}@wtpercentbox; } ###################################################################### +###### ###################################################################### +###### # this subroutine sums the numbers passed to it. Returns a single v +alue. # # ###################################################################### +##### sub sum { my $sum = 0; foreach my $line (@_) { $sum += $line; } return $sum; } ###################################################################### +###### ###################################################################### +###### # This subroutine disables and colors the wtpercentbox of the selecte +d # solvent in the Make Bath calculation window # MAIN -> MB -> COLORME ###################################################################### +##### sub colorme { our @wtpercentbox; my $i = shift; map{$_->configure(-bg=>'white')}@wtpercentbox; $wtpercentbox[$i]->configure(-bg=>'black'); map{$_->configure(-state=>'normal')}@wtpercentbox; $wtpercentbox[$i]->configure(-state => 'disabled'); } ###################################################################### +###### ###################################################################### +###### # This window is the about box for all windows # # MAIN -> ABOUT ###################################################################### +##### sub ABOUT #The about box in the help menu! { my $aboutwin = MainWindow -> new; $aboutwin -> title("About"); $aboutwin -> geometry("+210+210"); my $aboutleftframe = $aboutwin -> Frame() -> pack(-side => "left") +; my $aboutrightframe = $aboutwin -> Frame() -> pack(-side => "left" +); my $exitButton = $aboutrightframe -> Button( -text => "Close", -command => sub{destroy $aboutwin} ) -> pack(-side => 'right', padx => '10', pady => '10'); my $words = qq( BathCalc ver.2.0 Written by David Daycock. August 2004 david\@netboise.com); my $aboutText = $aboutleftframe->Scrolled('ROText', -height => '10', -width => '20', -wrap => "word", -scrollbars => 'osoe', ); $aboutText -> insert('end', $words); $aboutText -> pack(-side => "left", -padx => '10', -pady => '10'); } ###################################################################### +###### ###################################################################### +###### # This window is created when the Bath Volume button is pushed in the + # ratio window calculation screen. It will provide the volumes of ch +emical # to add to create a bath of known volume # RT -> RATIO -> RATIOSUP ###################################################################### +##### sub RATIOSUP { my $ratiowin = MainWindow->new; $ratiowin -> title("Bath Pour Up Instructions"); $ratiowin -> geometry("+200+200"); #Setting frames in main window. my $menuframe = $ratiowin -> Frame( -relief => "groove", -borderwidth => 2 )->pack( -side => "top", -fill => "x", ); my $topframe = $ratiowin -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, -pady => 5 ); my $midframe = $ratiowin -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, ); #command to make a file menubutton my $file_mw = $menuframe -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_mw -> command( -label => "Exit", -command => sub{$ratiowin -> destroy} ); my $help_mw = $menuframe -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_mw -> command( -label => "About", -command => sub{&ABOUT}); our (@ratioVol, @ratioVolbox, @ratio, %chemname); my @filledratio; my $i = 0; my $j = 0; my $k = 0; #foreach (@ratio){ # if ($ratio[$j] != 0){ # $filledratio[$k] = $ratio[$j]; # $k++; # } # $j++; #} foreach my $line (@ratio) { my $row = $i+2; $midframe->Label(-text=>$chemname{$i})->grid(-row=>$row,-c +olumn=>1); $ratioVolbox[$i] = $midframe->Entry(-bg=>'grey', -width => + 5, -textvariable => \$ratioVol[$i])->grid(-row=>$row,-column=>2); $i++; } }

Replies are listed 'Best First'.
Re: Need to Update Tk Widgets
by Grygonos (Chaplain) on Sep 01, 2004 at 16:36 UTC

    Without really digging through the code, let me offer this advice. Having the Entry widgets be tied to a scalar via the textvariable property is the best bet here. It should autoupdate (it does in my apps where I use them that way). Just make sure that when you run the calculation via the button callback that you (in the end) change the value of the referenced scalar to reflect the calculated value. Also another option would be simple reconfiguring the widgets via

    $widget->configure(-property=>'value');
    and simply manually reassign the value to be displayed in the entry

    update:Also after perusing the code abit, you might wanna take a look at Listing for 'our' @ Perldoc.com See if you really need our, or rather should just declare them all as my

    Hope some of that helps,
Re: Need to Update Tk Widgets
by Mr_Jon (Monk) on Sep 01, 2004 at 17:20 UTC
    Try replacing the following line:
    if ($totalmass != 0){@wtPercent = map{$_ / $totalmass}@wtPureAmt}else{ +$statustext = "You need to give me numbers!"};
    with its foreach equivalent:
    if ($totalmass != 0){ foreach (0 .. $#wtPercent) { $wtPercent[$_] = ($wtPureAmt[$_] / $totalmass); } } else { $statustext = "You need to give me numbers!" };
    I have not had time to fully read the docs but it seems as if reassigning the @wtPercent array using map is breaking its connection with -textvariable. I'm puzzled as to why this would be the case and would be interested to hear the full explanation from a more learned monk, but surprisingly the above works.
    Very nice GUI by the way.
Re: Need to Update Tk Widgets
by mawe (Hermit) on Sep 01, 2004 at 19:56 UTC
    Hi!

    I never used our, so all this looks a bit strange for me :-). Anyway, try the following:
    Change this

    our(@ratio, @ratiobox, @concentration, @wtPercent, @density, %chemname +); my (@concentrationbox, @densitybox, @wtpercentbox);
    to this:
    our(@ratio, @ratiobox, @concentration, @wtPercent, @density, %chemname +, @wtpercentbox); my (@concentrationbox, @densitybox);
    And this:
    map{$_->configure(-textvariable=>\$wtPercent[2])}@wtpercentbox;
    to this:
    map{$_->delete(0,'end')}@wtpercentbox; for my $i (0..$#wtpercentbox) { $wtpercentbox[$i]->insert('end',$wtPercent[$i]); }
    It should work now (I hope so :-))

    mawe