modifying a menu dynamically

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

modifying a menu dynamically

jWarrior
I have a top menu that looks like this:

File        Edit        Operation    etc.
 Open     Cut         Undo
 etc.         etc.        Redo

I want to change the Undo and Redo to have them say
just what they are about to undo or redo, e.g.
'Undo Remove class Foo'.  I have managed to grab
the CommandMenuItem object and can change its
description. What I don't know how to do is get the
menu to refresh itself to reflect the changes.

Note that I am -not- talking about popup menus here.
Thanks.

Donald


Reply | Threaded
Open this post in threaded view
|

Re: modifying a menu dynamically

Blair McGlashan
Donald

You wrote in message news:984dg4$mm6$[hidden email]...

> I have a top menu that looks like this:
>
> File        Edit        Operation    etc.
>  Open     Cut         Undo
>  etc.         etc.        Redo
>
> I want to change the Undo and Redo to have them say
> just what they are about to undo or redo, e.g.
> 'Undo Remove class Foo'.  I have managed to grab
> the CommandMenuItem object and can change its
> description. What I don't know how to do is get the
> menu to refresh itself to reflect the changes.

This sort of thing is done in #queryCommand: along with
enablement/disablement, e.g. see MethodBrowser>>queryCommand:, specifically
the handling of the #browseMethodClass command (4.0 has quite a lot of
examples, but I don't think they are in 3.0).

The commands will all be "queried" (i.e. the #queryCommand: methods of
Presenters, Views and Models on the command route will be invoked) when a
menu is opened, so you generally don't need to explicitly state that this
needs to be done. Sometimes it is necessary for commands that appear on
toolbar buttons - see senders of #invalidateUserInterface, many of which are
part of the framework and triggered at appropriate times such as changes of
selection, the execution of a command, etc, the overall result of which is
that it isn't often needed in one's own presenters.

>
> Note that I am -not- talking about popup menus here.
> Thanks.

Changing the #text: of a CommandQuery will affect all places that use that
same command, so if the same commands appear on a context menu then those
too would be updated.
Generally though one places context-sensitive commands on the context menu
(e.g. #browse, #delete), but one puts more specific commands on the menu bar
(e.g. #browseThis or #deleteThat) because one typically doesn't want the
menu bar to do different things depending on the selection.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: modifying a menu dynamically

jWarrior
Blair,

Thanks for your usual lucid explanation.

I was mucking about in queryCommand, but I was
modifying description instead of text.

It's always fun putting self halts in a queryCommand:.
I even remember to save my image first, most of
this time.

Thanks.

Donald


"Blair McGlashan" <[hidden email]> wrote in message
news:985l9k$dbaf$[hidden email]...

> Donald
>
> You wrote in message news:984dg4$mm6$[hidden email]...
> > I have a top menu that looks like this:
> >
> > File        Edit        Operation    etc.
> >  Open     Cut         Undo
> >  etc.         etc.        Redo
> >
> > I want to change the Undo and Redo to have them say
> > just what they are about to undo or redo, e.g.
> > 'Undo Remove class Foo'.  I have managed to grab
> > the CommandMenuItem object and can change its
> > description. What I don't know how to do is get the
> > menu to refresh itself to reflect the changes.
>
> This sort of thing is done in #queryCommand: along with
> enablement/disablement, e.g. see MethodBrowser>>queryCommand:,
specifically
> the handling of the #browseMethodClass command (4.0 has quite a lot of
> examples, but I don't think they are in 3.0).
>
> The commands will all be "queried" (i.e. the #queryCommand: methods of
> Presenters, Views and Models on the command route will be invoked) when a
> menu is opened, so you generally don't need to explicitly state that this
> needs to be done. Sometimes it is necessary for commands that appear on
> toolbar buttons - see senders of #invalidateUserInterface, many of which
are
> part of the framework and triggered at appropriate times such as changes
of

> selection, the execution of a command, etc, the overall result of which is
> that it isn't often needed in one's own presenters.
>
> >
> > Note that I am -not- talking about popup menus here.
> > Thanks.
>
> Changing the #text: of a CommandQuery will affect all places that use that
> same command, so if the same commands appear on a context menu then those
> too would be updated.
> Generally though one places context-sensitive commands on the context menu
> (e.g. #browse, #delete), but one puts more specific commands on the menu
bar
> (e.g. #browseThis or #deleteThat) because one typically doesn't want the
> menu bar to do different things depending on the selection.
>
> Regards
>
> Blair
>
>


Reply | Threaded
Open this post in threaded view
|

Re: modifying a menu dynamically

Blair McGlashan
Donald

You wrote in message news:986rvm$atn$[hidden email]...
>...
> I was mucking about in queryCommand, but I was
> modifying description instead of text.

If you do that you'll be modifying the underlying static description of the
command, which is probably not what you want.

> ...
> It's always fun putting self halts in a queryCommand:.
> I even remember to save my image first, most of
> this time.

:-). Breaking in #queryCommand: can be problematic because it is often
called during idle time to validate toolbar buttons etc. This occurs when
the #invalidateUserInterface message has been used to mark a window's
command enablement state as being in need of update. If this "validation" is
not allowed to complete, then the request is repeated until it is, and
consequently one can get a lot of walkbacks very quickly, usually
culminating in an untimely exit once resources have been exhausted.

It is possible to debug through queryCommand:, but one has to take care.
Here are a couple of tips:

1) Don't insert an unconditional breakpoint at the outermost scope - very
rapidly appearing walkbacks will result. Inserting the breakpoint inside one
of the command conditions will also result in multiple walkbacks, but
usually one can generally resume one of them (thus validating the UI of the
shell), and then use another of the walkbacks to start up the debugger.
2) Use a conditional breakpoint (especially if you really want to insert a
breakpoint at the outermost scope). This can be easily achieved using a
global variable and an expression such as 'A isNil ifTrue: [A := 1. self
halt]', which will only break the first time through, allowing one to then
debug away. One can reset the condition to have it fire again by setting the
variable to nil once more.
3) If a breakpoint in #queryCommand: is hit as a result of opening a menu
(which also initiates a command validation cycle) then you may find that
operation of the mouse and/or keyboard is impaired. This is because Windows
enters a very modal state when a menu is popped and it snaffles up some
input events. On WinNT/2K it is possible to get out of this modal state by
switching away to another application and back, e.g. using Atl+Tab. I can't
remember if this trick works on 95/98, but I have a feeling it doesn't.

There used to be a similar repeating walkback problem with setting
breakpoints in "paint" methods, although in that case death was even more
rapid. We worked around this issue by deliberately validating any view with
a WM_PAINT message on the stack when a walkback occurs, thus preventing
repeating WM_PAINT messages from Windows. One side effect of this is that
Windows may occassionally not repaint properly after a walkback, but this
was deemed acceptable at development time.

It occurs to me that we probably ought to employ a similar workaround for
#queryCommand:, and "validate" the user interface of any shell on the stack
in a queryCommand: when a walkback occurs, either due to a deliberately
inserted break, or an error. I will enter it onto our bugs system.

Regards

Blair