views:

437

answers:

3

This is going to be a generic question.

I am struggling in designing a GUI application, esp. with dealing with interactions between different parts.

I don't know how I should deal with shared state. On one hand, shared state is bad, and things should be as explicit as possible. On the other hand, not having shared state introduces unwanted coupling between components.

An example:

I want my application to be extendable in an Emacs/Vim sort of way, via scripts. Clearly, some sort of shared state needs to be modified, so that the GUI will use it. My initial plan was having a global "session" that is accessible from everywhere, but I'm not so sure about it.

One tricky use case is key bindings. I want the user to be able to specify custom keybindings from a script. Each keybinding maps to an arbitrary command, that receives the session as the only argument.

Now, the editor component captures keypresses. It has to have access to the keymappings, which are per-session, so it needs access to the session. Is coupling the editor to the session a good idea? Other components will also need to access the keybindings, so the session now becomes shared and can be a singleton...

Is there any good reading about designing GUI applications that goes beyond MVC?

This is Python and wxPython, FWIW.

[EDIT]: Added concrete usecase.

+2  A: 

If you've looked at MVC you're probably moving in the right direction. MVC, MVP, Passive View, Supervising Controller. Those are all different ways, each with their own pros and cons, of accomplishing what you're after. I find that Passive View is the "ideal", but it causes you to introduce far too many widgets into your GUI interfaces (i.e. IInterface). In general I find that Supervising Controller is a good compromise.

JMD
+1  A: 

In MVC, the Model stuff is the shared state of the information.

The Control stuff is the shared state of the GUI control settings and responses to mouse-clicks and what-not.

Your scripting angle can

1) Update the Model objects. This is good. The Control can be "Observers" of the model objects and the View be updated to reflect the observed changes.

2) Update the Control objects. This is not so good, but... The Control objects can then make appropriate changes to the Model and/or View.

I'm not sure what the problem is with MVC. Could you provide a more detailed design example with specific issues or concerns?

S.Lott
+3  A: 

Sorry to jump on this question so late, but nothing, I mean nothing can beat looking at the source of an application that does something similar. (I might recommend something like http://pida.co.uk, but there are plenty of extensible wx+Python IDEs out there as that sounds like what you are making).

If I might make a few notes:

  1. message passing is not inherently bad, and it doesn't necessarily cause coupling between components as long as components adhere to interfaces.

  2. shared state is not inherently bad, but I would go with your gut instinct and use as little as possible. Since the universe itself is stateful, you can't really avoid this entirely. I tend to use a shared "Boss" object which is usually a non-singleton single instance per application, and is responsible for brokering other components.

  3. For keybindings, I tend to use some kind of "Action" system. Actions are high level things which a user can do, for example: "Save the current buffer", and they can be conveniently represented in the UI by toolbar buttons or menu items. So your scripts/plugins create actions, and register them with something central (eg some kind of registry object - see 1 and 2). And their involvement ends there. On top of this you have some kind of key-binding service that maps keys to actions (which it lists from the registry, per session or otherwise). This way you have achieved separation of the plugin and keybinding code, separation of the editor and the action code. As an added bonus your task of "Configuring shortcuts" or "User defined key maps" is made particularly easier.

I could go on, but most of what I have to say is in the PIDA codebase, so back to my original point...

Ali A