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

Hello :),
Consider the following code.
my @sugs; @sugs=&suggestcomb($gotfile); #print "@sugs\n"; my $top = new MainWindow; my $lsugs=@sugs; #print"\nThe length of the array:"; #print "\n$lsugs"; $opt1="$sugs[0]"; $opt1='Nil' if !$opt1; #print "\n$opt1"; $opt2="$sugs[1]"; $opt2='Nil' if !$opt2; #print "\n$opt2"; $opt3="$sugs[2]"; $opt3='Nil' if !$opt3; #print "\n$opt3"; $opt4="$sugs[3]"; $opt4='Nil' if !$opt4; #print "\n$opt4"; my $l = $top->Label(-text => "Press right button\nfor popup menu.")->p +ack; my $m = $top->Menu(-tearoff => 0,font => "{arial} 12 {bold}",-menuitem +s => [ [Button => "$opt1", -command => \&replace1], [Button => "$opt2", -command => \&replace2], [Button => "$opt3", -command => \&replace3], [Button => "$opt4", -command => \&replace4], ] ); $top->bind("<Button-3>" => sub { $m->Popup(-popover => "cursor",popanc +hor => 'nw') }); } 1;
The number of strings returned by &suggestcomb and stored in @sugs may be different each time the subroutine is called.

I need to change the code so that we consider only the first four elements in @sugs, and so that there are as
many buttons in the pop-up menu as there are strings in @sugs.
For e.g if there are only two strings
in @sugs, we should have only two buttons, instead of four buttons, with the last two having the label "Nil" on them.

The max. no of buttons can be four,and the min. one.In case there are no elements in @sugs a single button should
display something like "None".

Right now the number of buttons is hard-coded to four.
Thanks in advance for any help.:)

Replies are listed 'Best First'.
Re: Tk Menu question.
by bbfu (Curate) on Sep 27, 2003 at 02:46 UTC

    First of all, don't use numbered variables. Use an array. Then you can use map to generate the anonymous array elements. (Oh, I renamed a few of your variables / functions to something more self-documenting.)

    #!/usr/bin/winperl use warnings; use strict; use Tk; my @menu_items = splice @{[get_menu_items()]}, 0, 3; @menu_items = ('None') unless @menu_items; my $mw = MainWindow->new(); $mw->Label(-text => 'Right-click for menu...')->pack(); my $m = $mw->Menu(-tearoff => 0,font => "{arial} 12 {bold}",-menuitems + => [ map { [Button => $_, -command => sub { replace($_) }] } @menu_items ]); $mw->bind("<Button-3>" => sub { $m->Popup(-popover => "cursor",popanch +or => 'nw') }); $mw->focus(); MainLoop; sub get_menu_items { return qw(); # return qw(Foo Bar Baz); # return qw(Foo Bar Baz Quux Zod Wibble); }

    The code to populate @menu_items is a little obfuscated, but not terribly. You could break it up into an if-else. *shrug*

    bbfu
    Black flowers blossom
    Fearless on my breath

      Hi:)
      Your code does exactly what I wanted to do! Really cool.
      Thanx a lot.
      Hi:)
      I missed this out earlier.Consider this bit of code.
      map { [Button => $_, -command => sub { replace($_) }] } @menu_items
      Is there a way to extract the label of that button in the menu, that the user clicks on,e.g. if the user clicks on
      the first button, the label 'Foo', if it is the third button,the label 'Baz', and so on.

      So that we can have a replace function like this:
      sub replace{ my $chosen="Label of button user clicked on"; + $t->insert('sel.first',"$chosen"); $t->delete('sel.first','sel.last'); $t->tagConfigure("rp",-foreground=>"black"); my $r=$t->search(-forwards,"$chosen",'end'); $t->tagAdd("rp","$r","$r wordend"); } 1;
      I need to use a replace function to replace a word marked by the sel tag in a text widget by the label of the menu button.

      Or else is it possible to call three subroutines,each being invoked when a particular menu button is clicked.Earlier
      my code was of the form:
      $m = $top->Menu(-tearoff => 0,font => "{arial} 12 {bold}", -menuitems => [ [Button => "$opt1", -command => \&replace1], [Button => "$opt2", -command => \&replace2], [Button => "$opt3", -command => \&replace3], ] ); sub replace1{ my $chosen1=$menu_items[0]; $t->insert('sel.first',"$chosen1"); $t->delete('sel.first','sel.last'); $t->tagConfigure("rp1",-foreground=>"black"); my $r1=$t->search(-forwards,"$chosen1",'end'); $t->tagAdd("rp1","$r1","$r1 wordend"); } 1; sub replace2{ my $chosen2=$menu_items[1]; ... } 1; sub replace3{ my $chosen3=$menu_items[2]; ... } 1;
      I tried this but it keeps printing only the first label, i.e. "Foo", even when we click on other menu buttons.
      sub replace{ my $chosen="$menu_items[$_]"; print "\nThe selected word:"; print "\n$chosen"; } 1;
      Thanks in advance.
      :)

        Actually, the code I posted is already sending the label to the replace subroutine (that's why it's sub { replace($_) } and not \&replace).

        Just start out your replace sub like this:

        sub replace { my $label = shift; ... }

        bbfu
        Black flowers blossom
        Fearless on my breath

Re: Tk Menu question.
by Anonymous Monk on Sep 26, 2003 at 08:23 UTC
    That code doesn't compile ;(
      It's not supposed to compile.It's only a section of code. I thought that would be pretty obvious, since there is no
      text widget defined in the code(within which the pop-up is required), the code for the subs &suggestcomb, replace1, replace2, etc... is not supplied, the value for $gotfile is not defined, no use Tk;etc,etc.

      My question was only regarding controlling the number of buttons in the pop-up menu.