GUI separate from the backend code

This issue is often a lot more complex than it sounds. Tips welcome and appreciated. Good idea!

Examples: Chess in Tcl, TclMusic, tclchat.

RS 2003-08-21: I often make it a rule to design an app in terms of a Tcl API that does not require Tk. All functionality is available over proc calls. In a second step I design a GUI and add visualisation of app objects and triggers - buttons or menu items that call one of the API commands; labels with textvariables that further control the APIs action.

DKF: This is an instance of the sort of Separation of Responsibilities stuff that you see a lot in (good) professional software.

Bryan Oakley: This topic interests me greatly. The way I solve this problem is to use what I call actions (and some day, I swear, I'll write up a paper on the subject). actions are, in effect, the public API of a program. I try to stick to the following rule of thumb: anything a user can do from the UI must be done via an action. Thus, my code tends to look like this:

    action define cut {} {<perform 'cut' functionality>}
    action define copy {} {<perform 'copy' functionality>}
    action define paste {} {<perform 'paste' functionality>}
    .menubar.editMenu add command cut [list action invoke cut]
    .popup add command cut [list action invoke cut]
    bind . <<Cut>> [list action invoke cut]
    button .toolbar.cutButton -command [list action invoke cut]

For the record, "action" is a command I wrote which is mostly just a glorified proc command, but has some extremely useful additional features.

The benefit is that, for one, it lets you implement several ways for the user to access a function without having to duplicate code. You can have a "cut" toolbar button, a "cut" item on the edit menu, a "cut" item on a popup menu, a "cut" keyboard accelerator, a "cut" function key, etc., all running the same code. Adding a new way to access the functionality becomes trivial. For example, when developing code I usually just start with a menubar and maybe a toolbar. After things are running I'll add accelerators, popup menus and the like, and that is all very simple.

Another benefit is that it becomes easy to drive the interface via a script (for testing, for example), or to rewrite all or part of the UI without having to rewrite any of the actual inner workings of the code. It's also possible to have a macro capability where you can string several actions together in a script, and also makes remote control of the app fairly trivial.

DKF: This reminds me of Java actions (instances of javax.swing.Action IIRC - I don't need to remember because I have searchable documentation :^D) though they have some additional cuteness to them so that you can join them easily to buttons, toolbars, menus, etc. and have them all use the right kind of localized label and icon (with suitable hotkeys, etc.) as well as the invokation bit.

Bryan Oakley: At one point I had a lot of this cuteness too -- I could do "action configure foo -label "Do Foo"" and all the menu items and toolbar buttons and documentation and so on would all Do The Right Thing. In practice this seemed more trouble than it's worth. I did retain one bit of critical functionality: when I create widgets I register them with the action they perform ("action associate fooAction") and I can enable or disable them all in one fell swoop ("action disable fooAction").

This is a huge win because I don't have to manually enable or disable several widgets when availability of a function changes, and if I add a new widget I don't have to add it everywhere I have to enable or disable the functionality.

ulis, 2003-08-21: I do the things the other way of RS. I design the user interface and then add the actions needed (in the Bryan Oakley sense). Sometimes I need to slightly modify the UI during the second step.

Charlie What about the other way around? "actions" are defined as being 'things' that originate somewhere in the GUI (view) (a button is pressed), but sometimes 'things' originate from somewhere in the core (model,controller MVC). How is this supposed to be implemented in an efficient/consistent/clear way in Tcl. Or stated otherwise:

        View -> Model/Controller    is no problem (as described above), 
        Model/Controller -> View    ?

RS: see Model / View / Controller - easiest done with textvariables, or variable traces.

Charlie But this requires strong bindings (hard coded) between the Gui (view) and the Core (Model/Controller). How can one avoid this so that true reuse of gui code / core code can be the result?

RS: This is where the above-mentioned API comes in - provide "methods" for setting values or taking actions, and "callbacks" to fire when the model changed.

ulis: I don't consider the use of callback as strong binding. And reuse is not my motivation. Efficiency, maybe.

escargo 21 Aug 2003 - The actions discussed above remind me of the virtual events. The action code does not care about the source of the events, only that they happened.

TV I'd say it's not so much 'virtual' as 'properly named' in a protocol where the relations between program actions and user interface components are not linked by some invisible and hard to trace pointer relationship, but designed to be understandable and formally tracable. That such idea of 'streaming' a even heavy graphics protocol can work is proven by every unix/linux machine with X on it. Not that X is necessarily overseeable, but often preferable over a lot of hidden object calling which can unnecessary far from what one actually wants to program.

The model view controller idea I think is fine from literature, I guess events (as in the tcl fileevent, and graphics events with callbacks) could be translated to a message on a stream to get the idea. Which of course still leaves you to act upon them, but possibly neater way.

(13-6 '04) Maze in openGL om windows navigation controlled by Tcl/Tk is an example of what this page is about, using a tcl/tk front end and a C/OpenGL based 'back'-end.

The separation of GUI and logic is also emphasised in BOOK Effective Tcl - Writing Better Programs in Tcl and Tk.

Another good reference is a paper on the Humble Dialog Box [L1 ] by Michael Feathers. The language is C++, but the concepts are good.