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

Hi,
I have a Perl Tk text widget window in which this button amongst several others are defined:
$f->Button(-text => "Sug", -command =>\&tged)->pack(-side => 'right');
The subroutine tged is called when the button is clicked. Here is the code for the sub:
sub tged { @chars=$t->get('sel.first','sel.last'); + #Extract chars in area selected by user and store in @chars. #print "\nSelected word:"; #print @chars; open TF,'>gotword.txt' or die $!; #Write sel +ected word onto file. print TF @chars; close TF; $gotfile="gotword.txt"; #Save file +name in $gotfile. @sugs; #Array for + holding strings returned by &suggestcomb. @sugs=&suggestcomb($gotfile); #Call sub. &suggestcomb passing $gotfile as parameter. #print"\nStrings in main:"; #print "@sugs\n"; $top = new MainWindow; #Create new main window which pops up when #the user selects a word and clicks on the 'Sug' button. $lsugs=@sugs; #Length of + the array @sugs. $opt1="$sugs[$lsugs]"; #Last element in the suggestion array. $opt2="$sugs[$lsugs-1]"; #Second last element in the suggestion array. $opt3="$sugs[$lsugs-2]"; #Third last element in the suggestion array. $l = $top->Label(-text => "Press right button\nfor popup menu.")->pack +; #Text label for new main window. #Menu displayed in new main window. $m = $top->Menu(-tearoff => 0,font => "{arial} 12 {bold}", + -menuitems => #Menu items displ +ayed as buttons. [ [Button => "$opt1", -command => \&replace1], #Labels of buttons are the strings obtained from @sugs. [Button => "$opt2", -command => \&replace2], [Button => "$opt3", -command => \&replace3], ] ); #When a button is clicked the corresp. sub. for replacing is invoked. $top->bind("<Button-3>" => sub { $m->Popup(-popover => "cursor",-popan +chor => 'nw') }); } 1; #Subroutines to replac +e words with selected strings. sub replace1{ $chosen=$opt1; $t->insert('sel.first',"$chosen"); #Insert selected suggestion at the start point of the word to be repla +ced i.e. at sel.first. $t->delete('sel.first','sel.last'); #Delete the word to be replaced. $t->tagConfigure("replaced",-foreground=>"black"); $t->tagAdd("replaced","sel.first","sel.last"); } sub replace2{ $chosen=$opt2; $t->insert('sel.first',"$chosen"); $t->delete('sel.first','sel.last'); $t->tagConfigure("replaced",-foreground=>"black"); $t->tagAdd("replaced","sel.first","sel.last"); } sub replace3{ $chosen=$opt3; $t->insert('sel.first',"$chosen"); $t->delete('sel.first','sel.last'); $t->tagConfigure("replaced",-foreground=>"black"); $t->tagAdd("replaced","sel.first","sel.last"); }
Before clicking the button 'Sug' which calls the tged subroutine, the user clicks another button which invokes
another sub.(code not shown.)This changes the font color of some words in the window to red with code like this:
$t->tagConfigure("ch_clr",-foreground=>"red"); $t->tagAdd("ch_clr","$start","$end_pt");
Then the user selects a word which is in red colour, (the ' sel' tag gets that word)and clicks on the 'Sug' button.

The sub. &tged is invoked. Then &tged passes the selected word to &suggestcomb,which processes the word in some way
and returns a list of words in the array @sugs.

This list of words is displayed as a popup menu against the selected red word.The user clicks on a word from the menu,
which replaces the previous red coloured word.The replaced word should be black coloured now.

In the subs &replace1,&replace2,&replace3 I've reset the colour of the replaced word to black.
$t->tagConfigure("replaced",-foreground=>"black"); $t->tagAdd("replaced","sel.first","sel.last");
**********
But the word remains red.What is the prblem here?
**********

Also each time we select a red word and click on 'Sug' the subroutine &suggestcomb returns a new list of words
in @sugs to display. The number of words returned each time may be different.

***********
Is it possible to have exactly the same number of buttons in the popup menu as the number of words to display?
***********

Right now I've hard-coded the pop-up menu to have three buttons.But if there are less than three words,
say only one word to display from @sugs,then two of the buttons have no labels, they remain blank.
At the same time I need to fix the number of words to display, say not more than the first 5 words in @sugs.

One more question.Suppose we select one red word(word1), click on 'Sug', click on a word from the pop-up menu to replace
the red word.

Then we do the same thing for another red word(word2). The same list of words gets displayed as for word1.The
new list of words from @sugs is not displayed.

The new list of words i.e.for word2 gets appended at the end of @sugs, so I've tried taking the elements of
@sugs towards the end.Still some words of the list for word1 are displayed.

Is there some way we can empty @sugs after displaying the list for word1, so next it contains only the list for
word2, and so on. I've tried popping all the elemnts but this code does not seem to do the trick:
$lsugs=@sugs; print"\nThe length of the array:"; print"\n$lsugs"; for($elt=0;$elt<$lsugs;$elt++) { pop(@sugs); } print"\nThe array contents after popping:"; print "@sugs\n";
Whew! That's about all .Please help
:)

Replies are listed 'Best First'.
Re: Perl Tk Text widget question
by CombatSquirrel (Hermit) on Aug 27, 2003 at 10:12 UTC
    After you execute $lsugs=@sugs;, keep in mind that the arrays are 0-indexed, so the last element of the array is not $sugs[$length], but $sugs[$length - 1]. You should rewrite the assignment code as follows:
    @opts[1..3] = @sugs[-1..-3];
    Also, at the line
    $t->tagAdd("replaced","sel.first","sel.last");
    the word is already replaced, meaning that the text may not even have the specified length any more.
    Furthermore, think of use strict; use warnings; and you'll get a lot of useful information on where your code might be behaving differently from what you expect.
    Hope this helped.
    CombatSquirrel.
    Update: Fixed typo, thanks to ybiC.
    Entropy is the tendency of everything going to hell.
      Hi,
      sorry for the much delayed reply.Yes, I overlooked the array indices part.

      But the problem of @sugs not containing a new list of words each time the sub &tged is executed, is not
      really because of @sugs.i.e

      @sugs=&suggestcomb($gotfile);

      Here @sugs will get overwritten completely each time &suggestcomb returns a new list of words.So the problem
      is in &suggestcomb

      You are right about the colour change bit too. I've changed the code now to:
      sub replace1{ my $chosen1=$opt1; $t->insert('sel.first',"$chosen1"); $t->delete('sel.first','sel.last'); $t->tagConfigure("replaced",-foreground=>"black"); my $r1=$t->search(-forwards,"$chosen1",'end'); $t->tagAdd("replaced","$r1","$r1 wordend"); #print"\nThe start pos of the pattern:"; #print "\n$result"; }
      Got a better way to do the above?Because I don't like the idea of having to search the text.Moreover the colour
      still does not change sometimes..?
      Thanx :)