Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dynamic cascade menu

193 views
Skip to first unread message

Marc Girod

unread,
Mar 25, 2011, 1:11:31 PM3/25/11
to
Hello,

I try to modify an existing program, which currently initializes
statically a menu hierarchy.
I'd like to defer this to later.

Here is a code snippet (complete and running, even if stupid), which
shows my (wrong) expectation:

-8<-------------
#!/usr/bin/perl
use strict;
use warnings;
use Tk;

my $mw = MainWindow->new;
$mw->optionAdd('*Menu.tearOff',0);
$mw->optionAdd('*Menu.font','Arial 12 bold');

my $frame = $mw->Frame(-width => 200, -height => 240)->pack;
my $but = $frame->Menubutton(-text => 'Foo', -underline => 0)->pack(-
side => 'left');
my $menu = $but->Menu(-tearoff => 'false');
$but->configure(-menu => $menu);
my $sub = $menu->Menu(-tearoff => 'false');
$menu->add('cascade', -label =>'Bar', -command => \&foo, -menu =>
$sub);
$menu->postcascade(0);
$sub->add('radiobutton', -label =>'Zoo');

MainLoop;

sub foo {
print "foo\n";
}
-8<------------------

It defines one button, labelled 'Foo', from which opens a menu, with
one entry 'Bar', from which opens a cascading menu, with now only a
radio button, 'Zoo'.
I'd like to create the list of radio buttons only as late as possible,
i.e. just before posting the menu.
I thought this would happen by registering a 'foo' command callback,
but this one is never invoked.

So my questions:
- why isn't it invoked?
- how should I register it instead of how I do?
- is my idea otherwise bad, and if so why?

Thanks,
Marc

smallpond

unread,
Mar 27, 2011, 12:46:28 PM3/27/11
to

-command is used in Menus to indicate a callback executed when a
selection is made within the menu.

-postcommand is a callback that is made just before the menu is
posted
which is what you're looking for. Not sure whether
you can make changes to the menu this late, but I don't see anything
that says you can't.

I've never tried what you're doing so I don't know if it will work.
You could also try using a regular button which when pressed generates
the menu that you want and displays it. Good luck.

Marc Girod

unread,
Mar 27, 2011, 3:15:24 PM3/27/11
to
On Mar 27, 5:46 pm, smallpond <smallp...@juno.com> wrote:

> -command is used in Menus to indicate a callback executed when a
> selection is made within the menu.
>
> -postcommand is a callback that is made just before the menu is
> posted which is what you're looking for.  Not sure whether
> you can make changes to the menu this late, but I don't see anything
> that says you can't.

Thanks!
I was looking at the wrong spot in the Tk::Menu pod/man page:

CASCADE ENTRIES
...
If a -command option is specified for a cascade entry then it
is
evaluated whenever the entry is invoked. This is not supported
on
Windows.

postcommand is an option at Menu creation:

WIDGET-SPECIFIC OPTIONS
Name: postCommand
Class: Command
Switch: -postcommand

There it works!
Thanks.
Marc

Marc Girod

unread,
Mar 29, 2011, 7:46:00 AM3/29/11
to
On Mar 27, 8:15 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> There it works!

I am not quite done with my change, and again stuck.
Now that I do not create all the sub menus in advance,
I could have only one shared stub.
Only, is there a way for to know which cascade menu it was invoked
from?
Again my small, modified demo:

-8<----


#!/usr/bin/perl
use strict;
use warnings;
use Tk;

my $mw = MainWindow->new;
$mw->optionAdd('*Menu.tearOff',0);
$mw->optionAdd('*Menu.font','Arial 12 bold');

my $frame = $mw->Frame(-width => 200, -height => 240)->pack;
my $but = $frame->Menubutton(-text => 'Foo', -underline => 0)->pack(-
side => 'left');
my $menu = $but->Menu(-tearoff => 'false');
$but->configure(-menu => $menu);

my $sub = $menu->Menu(-tearoff => 'false', -postcommand => \&foo);
for (qw(Apple Orange Banana)) {
$menu->add('cascade', -label =>$_, -menu => $sub);
}
$menu->postcascade(0);
my $i = 0;

MainLoop;

sub foo {
$i++;
$sub->delete(0, 0);
$sub->add('command', -label =>"Zoo $i");
}
-8<-----------

In foo, I would of course add different sets of options for the
various fruits.

I am stuck in my actual code (couldn't so far narrow down what
interfers) with what looks like a stack corruption. I.e. the
equivalent variable for $i gives something very strange.

I tried to debug this (with perl -d) but only to notice that Tk and DB
both claim the same 'caller' so that my breakpoints just hang...
Are there known recipes for this kind of woes?
Oops... I didn't search the FAQ for that answer...

Thanks,
Marc

Marc Girod

unread,
Mar 29, 2011, 9:41:21 AM3/29/11
to
On Mar 29, 12:46 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> I am stuck in my actual code (couldn't so far narrow down what
> interfers) with what looks like a stack corruption. I.e. the
> equivalent variable for $i gives something very strange.

I got this one!
I was passing an argument to the callback, and expecting it would be
evaluated at definition time:

my $n = 2;


my $sub = $menu->Menu(-tearoff => 'false', -postcommand =>

sub{foo($n)});

But now, I know even only the /address/ of $n is actually used there.

My other two questions remain.

Thanks,
Marc

Marc Girod

unread,
Mar 30, 2011, 4:48:38 PM3/30/11
to
On Mar 29, 2:41 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> My other two questions remain.

OK, one more.
How do I empty a menu?
There is a delete function which takes a range, but how do I know the
lenght?
Do I have to record it myself?

Marc

Steve C

unread,
Mar 31, 2011, 9:35:35 AM3/31/11
to

A new question should be in a new post, not a reply to a different question.

Index doesn't have to be a number. Check perldoc Tk::Menu
in the section titled WIDGET METHODS

delete(0, 'end')

Marc Girod

unread,
Mar 31, 2011, 2:46:19 PM3/31/11
to
On Mar 31, 2:35 pm, Steve C <smallp...@juno.com> wrote:

> Index doesn't have to be a number.  Check perldoc Tk::Menu
> in the section titled WIDGET METHODS
>
> delete(0, 'end')

Thanks. Taken into use. Works well.
I cannot see how I missed it... I thought it was only for text
entries...

Marc

0 new messages