Avoiding spaghetti in GUI instance hierarchies
In my experience, when designing GUI objects, you tend to end up building fairly large instance hierarchies. Objects at low levels in different hierarchies need to know about each other, so there is a temptation to create ad-hoc cross-references between them, which can lead to code resembling that famous pasta.
Even in our small example, we can see this just beginning to happen. The action objects need to know about the currently selected item in the table viewer. The question is: What object does the action store? Is it the table viewer, the SWT table itself? The window?
Figure 6. Windows, widgets, and actions
![Figure 6. Windows, widgets and actions](https://i-blog.csdnimg.cn/blog_migrate/99da31dd5c6fcbb560662aa0df7b072b.png)
One solution is to funnel all the access to widgets/selection objects through the window. Have each action store the window that created it, then it can use the accessor methods on that window to get to the objects it needs.
If you want to share actions between different windows where the widgets are accessed using different method names, you can wrap the access to the widgets from the action inside a method, which could be reimplemented in subclasses of the action to fetch the correct widget. For example, to share an action that needed to access a selection, the method getSelection()
in the superclass could be implemented as window.getTableSelection()
in one subclass and (say) window.getThirdListViewerSelection()
in another subclass.
Making actions context-sensitive
Another thing we can do with actions is to make them aware of what is happening in the rest of the window and adapt themselves accordingly. We're going to make OpenAction
listen for any changes to the current selection in the table viewer. When it notices a change, it can look at the new selection and change its text, tool tip, and enabled state to reflect that.
OpenAction
launches the "associated" program on the currently selected file. If nothing is selected then, rather than letting it run and report an error or just mysteriously do nothing, why don't we disable the action?
While we're thinking about being nice to the user, I often get confused when I see menu items that are disabled and I don't understand why they are disabled. So, here's an idea: How about changing the tool tip so that we even tell the user why the action is disabled?
We also have to decide what to do if the selection includes several files. Well, we could just run them all, one after another, but, since I have painful memories of selecting 300 files and choosing the Open option from the Windows File Explorer, let's just disable it for now.
Finally, we'll check if the selected item is a folder and disable the open action in this case, as well.
We need to make OpenAction
a listener for the SelectionChanged event from the table viewer, so we'll make it implement ISelectionChangedListener (Listing 8).
We'll do this in selectionChanged()
:
- Set the text and tool tip text to the default.
- Check the selection.
- If we don't have exactly one item selected, we disable the action, adjust the tool tip to say why it is disabled, and return.
- If the selection is a file (rather than a folder), then we adjust the text and tool tip to reflect that file name and enable it.
Extract from Using the Eclipse GUI outside the Eclipse Workbench, Part 3: Adding actions, menus, and toolbars
1.Action只须调用Window的方法,而不关心Window里控件的细节;
2.Action要根据当前的选项而变化,所以需要在选项变化时通知Action。