Java Forum / GUI / June 2006
What is the design pattern for GUI menu/toolbar activation
timasmith@hotmail.com - 20 Jun 2006 00:49 GMT So suppose you have a complex frame with multiple panels and depending on the state of specific controls on the panels - you should enable or disable menus and toolbars accordingly.
Menus have a workaround in that you could perform logic on 'click' - but what about toolbars.
If I select text so copy and cut should be enabled. If a click on a node so my delete button should enable.
I want to avoid polling the entire frames state every second of course.
Perhaps I could have some kind of property listener for the relevant controls that on change changes (de)activates the toolbar - but the cut/copy example shows the impracticality of that.
There must be a design pattern for this...
Tim
Phlip - 20 Jun 2006 01:11 GMT timasmith wrote:
> I want to avoid polling the entire frames state every second of course. Observer Pattern, from the book /Design Patterns/. It decouples the target from the observer, so neither knows the other's type.
When you discover that you typically have a triangle of observers, then you have Model-View-Controller.
 Signature Phlip http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!
Chris Uppal - 20 Jun 2006 09:57 GMT > > I want to avoid polling the entire frames state every second of course. > > Observer Pattern, from the book /Design Patterns/. It decouples the target > from the observer, so neither knows the other's type. In particular, since you are posting in Java groups, look into the buttons' Actions.
-- chris
wizofaus@hotmail.com - 21 Jun 2006 00:20 GMT > > > I want to avoid polling the entire frames state every second of course. > > [quoted text clipped - 3 lines] > In particular, since you are posting in Java groups, look into the buttons' > Actions. Even within what Java/Swing supplies, there still seems to be a good deal of room for various implementations. For instance, if you have cut & copy buttons in a toolbar, the chances are they can apply to more than one control in your application: you may have text-editing controls (JTextComponent derived), and you may also have some other sort of object manipulation editor. Usually then the buttons need to enabled if and only if some control is focused that can currently support the relevant action. Problem is, there isn't really a consistent interface to determine when that state may change and how to query it. For a JTextComponent, usually you'd want to add a CaretListener that sets the Actions' enable status depending on whether there is text selected. But there may be other events that cause whether text is selected to change, for instance, programmatically changing the text on the underlying document, that are not trapped by this. For some other sort of control, there may be a rather different way of trapping whether the current selection has changed. And then you need to way of trapping every time focus is moved from one control to another, just in order to determine which control should be determining whether the commands are enabled. Further more, while there is built-in support for controlling the enable status of buttons, the same is not true for the "selected" state, i.e. for toggle-style buttons that may reflect attributes of the current selection (e.g. the "Bold" button in a word processor).
I have to say, after spending some time trying to get all this to work for me, MFC's command update mechanism, which basically constantly refreshes the status of all toolbar buttons every time there is a lull in the windows message queue, is a good deal simpler to work with. You never have to worry about which listeners to install, and 90% of the time it correctly takes care of automatically querying the currently focused window/control. I'm actually curious if someone has attempted to emulate this in Java - if not, I'm extremely tempted to do so myself. I doubt there would be a way to trap "idle" message queue events, but even if it works by polling at a fixed interval, it would do the job.
Chris Uppal - 21 Jun 2006 11:08 GMT > Problem is, there isn't really a > consistent interface to determine when that state may change and how to [quoted text clipped - 4 lines] > changing the text on the underlying document, that are not trapped by > this. I think the underlying problem here is trying to tie the activation state of the Action to overly low-level implementation state. If the Action, say, is a Listener itself (which is how I would probably want to set it up) then it wouldn't listen to the state of the text component, but to the state of the /application/ -- since it's the application which knows whether the corresponding operation is applicable at <some instant in time>. Granted that that is more work to set up, and may also be foreign to the way some programmers think about application structure.
> I have to say, after spending some time trying to get all this to work > for me, MFC's command update mechanism, which basically constantly > refreshes the status of all toolbar buttons every time there is a lull > in the windows message queue, is a good deal simpler to work with. The system (not Java or MFC) I work with most uses that implementation technique too. It uses the idea of an "action" (which talks to the application, not the low-level components) as above, but doesn't use the Observer pattern. It just updates the enabledness (and related aspects) of command widgets whenever idle time starts. It's a hack, but it does work well in practice -- being simple, reliable, and requiring little maintenance.
-- chris
wizofaus@hotmail.com - 22 Jun 2006 02:30 GMT > The system (not Java or MFC) I work with most uses that implementation > technique too. It uses the idea of an "action" (which talks to the > application, not the low-level components) as above, but doesn't use the > Observer pattern. It just updates the enabledness (and related aspects) of > command widgets whenever idle time starts. It's a hack, but it does work well > in practice -- being simple, reliable, and requiring little maintenance. I actually don't see it as a hack at all...it seems exactly the right sort of thing to use idle processing for. Unfortunately I can't see anyway of doing it portably using standard Java - although the AWT toolkit (or more specifically, the singleton AWTAutoShutdown object) is notified every time the Windows message queue goes idle, there's no way of overriding what happens at this point (you can't override creation of the AWTAutoShutdown object to do the necessary subclassing). And as for what happens on other platforms, who knows. Which probably leaves as the only realistic option using a timer, which is definitely slightly hackish, but trying to manually keep track of every single event that can modify toolbar button state is really not feasible (for instance, if someone copies something to the system clipboard in another application, your own app's Paste button might get disabled if the data format is not supported).
Chris Uppal - 23 Jun 2006 15:40 GMT [me:]
> > It just updates the enabledness (and related > > aspects) of command widgets whenever idle time starts. It's a hack, [quoted text clipped - 3 lines] > I actually don't see it as a hack at all...it seems exactly the right > sort of thing to use idle processing for. Well, hack or not, I agree that there doesn't seem to be a way to hook idle time in Java.
> Which probably leaves as the only realistic option using a timer, which > is definitely slightly hackish, <nods sadly/>
-- chris
Chris Uppal - 22 Jun 2006 16:08 GMT > So suppose you have a complex frame with multiple panels and depending > on the state of specific controls on the panels - you should enable or > disable menus and toolbars accordingly. I happened across this article today while looking for something completely unrelated:
http://www.jot.fm/issues/issue_2004_05/column6
I have only skimmed it very quickly, but it may have some useful ideas.
-- chris
wizofaus@hotmail.com - 22 Jun 2006 23:48 GMT > > So suppose you have a complex frame with multiple panels and depending > > on the state of specific controls on the panels - you should enable or [quoted text clipped - 6 lines] > > I have only skimmed it very quickly, but it may have some useful ideas. Nothing to do with updating the state of toolbar buttons/menu items depending on the state of the currently active control etc.
One comment interests me "...what if many components are interested in a text-field action? I suggest that if this occurs, we are too tied to the components. That text-field should be treated as a controller in a model-view-controller design pattern. A control should alter a model. Views that are interested in the model should be observing the model, not the controller."
But that doesn't strike me as realistic. For instance, my application's primary view allows manipulation of objects such as boxes, lines and text-boxes. The "cut", "copy", "paste" and even "undo" and "redo" actions while you are working in that view applies to whole objects. But you can also click on a text-box object to edit the underlying text. Once that becomes the current control, then "cut", "copy", "paste", "undo" and "redo" are all handled by the text-editing control. I don't see how it could be handled by any sort of "model" in the traditional M-V-C pattern. So instead I have to supply code to route the actions that each toolbar button fires down to the currently active control. And note that detecting the currently active control is not completely trivial - the only way I've found of doing it reliably is to add a FocusListener to each button, and store a reference to the component that previously had the focus. Using the ActionEvent source or the KeyboardFocusManager's focus owner don't help, as they both point to the actual toolbar button itself.
Chris Uppal - 23 Jun 2006 16:06 GMT [me:]
> > http://www.jot.fm/issues/issue_2004_05/column6 > > > > I have only skimmed it very quickly, but it may have some useful ideas. > > Nothing to do with updating the state of toolbar buttons/menu items > depending on the state of the currently active control etc. Ah, well... Apologies for the misdirect, I thought it looked relevant, but you are right, it is not.
> One comment interests me > "...what if many components are interested in a text-field action? I [quoted text clipped - 13 lines] > control. I don't see how it could be handled by any sort of "model" in > the traditional M-V-C pattern. I agree, but I don't think that sort of event was what the quoted passage was referring to. I take it to mean that if we are interested in, say, whether the text field contains a valid number, then we should be Observing the state of the text field's Model -- if that is a String (or some sort of value holder containing a String) which parses as a valid number then other UI elements will update themselves accordingly.
But the specific actions you mention are not Model-related in the MVC sense -- they are, I think, the responsibility of the Controller. What you have is a pattern where you have a sort of generic controller-like object, installed near the application's top level, which responds to user input by finding another contoller and invoking that controllers' specific cut, paste, or whatever code. And....
> So instead I have to supply code to > route the actions that each toolbar button fires down to the currently > active control. And note that detecting the currently active control > is not completely trivial .... as you note, that isn't too simple.
(BTW, the non-Java UI system I mentioned before has exactly the same problem with buttons and toolbar buttons with invoke actions "for" some other component.)
-- chris
-- chris
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|