GUI Builders (was: More On Multiple Inheritance)

Hans-Dieter.Dreier@materna.de Hans-Dieter.Dreier@materna.de
Mon, 17 May 1999 16:01:31 +0200


--wF9BjfqF5aIGMkqIyBTlcsGcxqpDzE31
Content-type: text/plain; charset="ISO-8859-1"
Content-transfer-encoding: quoted-printable

>Hans-Dieter.Dreier@materna.de wrote:
>
>> If we use the instance layout of the target class for templates as well,=
 a
>> simple copy constructor can be used as a creation routine. As an additio=
nal
>> benefit, editor (and debugger) can then be used to view "live" configure=
d
>> instance items as well as templates.
>
>This strikes me as basically a prototyping scheme, at least on the
>data.  You're talking about having templates (prototypes) which can have
>the same impl but differ in their state.  And these can in turn be used
>as a prototype for another template.

Yes.

>> Methods are almost always class items since all of the instances share t=
he
>same
>> method code. Message handlers are instance items, however. IMO it is a m=
ajor
>> design flaw to implement message handlers as class items since this
>effectively
>> prohits reuse of that class. Message handlers often need to access the n=
ame
>> space of the _instance_ rather than that of the _class_. If all the cont=
acts
>to
>> the instance's environment would have to take place by dynamic dispatch,
>such a
>> class would be rather cumbersome to use.
>
>I don't think so.  If the widget classes are set up to use observers,
>the widgets are reusable and don't need to be written with any
>particular message handler in mind.  Ideally the widget, handler and the
>data are totally separate classes, providing more flexibility.  Hence
>handlers should never need to be in the widget.  Java 1.0 joined them
>together - they replaced that model with observers in 1.1.

But isn't that a bit heavy for many applications? The model that I have in =
mind would allow that, too, but you'd also have the ability to simply speci=
fy s.th. like this:

PushButton: pkOK
 ...
 Mesage Actions
  On ButtonClicked          // ButtonClicked =3D *predefined constant* for =
message
   sUser =3D dfUser.text
   sPassword =3D dfPassword.text
   Parent.WindowClose (true)

and it possibly would override an inherited message handler for this partic=
ular message.
You would specify this in the same way you specify a data property.
You could use any names in the context of this template definition,
especially those of the parent window (the window in which this button is d=
isplayed), without any qualification needed.

If the programmer wants to see what happens if the button is clicked,
he/she simply looks at the buttons definitions, and there it is. No need to=
 look into any other objects or classes; it all is in one place.

BTW, this is an example of a consideration one should bear in mind when pro=
gramming OO: OOP sometimes tends to rip aspects of items apart that are bet=
ter localized in one place. Message handlers are a good example. If they ar=
e highly individual (each instance does it differently), why not specify th=
e actions to be taken with each template? =


Another example would be an abort button. Usually, every abort button does =
the same thing: It simply closes its parent window. Here it is sensible NOT=
 to specify the message handler with each instance, but rather derive from =
a template that already has a message handler with the desired behaviour. T=
his is possible because in this case no names of the instantiation namespac=
e need to be known; the parent window can be determined by a feature call.

This is the way Centura does it; and I can tell from a lot of project work =
that I always found it very convenient and way better than how it is done i=
n VC++ or Delphi.

>> Dynamic creation of identically configured objects by a program is possi=
ble
>by
>> calling the creation routine multiple times for a given template. In thi=
s
>case
>> the instance created by the declaration might be unwanted;  we might wan=
t to
>be
>> able to prevent automatic creation due to the declaration.
>
>If this sort of thing ever happened, I would prefer it to be an
>optimisation, I'm not sure I'd want to give it language status, even
>though this sort of thing could really happen in any situation.

Maybe you're right here - it is rather specific to GUI applications.

>> We could do this by
>> either adding a key word ("template") to the declaration or by adding a
>special
>> outline item (folder) for such templates. The latter is better because t=
he
>> former would either disrupt the instance layout or leave a NULL referenc=
e
>gaping
>> if used in the "instance items" section of a class.
>
>I'm not sure what you're proposing here.  Could you elaborate?

Forget it - I found a better solution that makes do with standard features.
Look at a normal dialog window. It would look like this:

DialogWindow: dlgLogin
 ...
 Instance items
  DataField: dfUser
  DataField: dfPassword
  PushButton: pbOk
  PushButton: pbCancel
 ...

Each instance of dlgLogin creates one instance of each of its children (dfU=
ser, dfPasswordc, ...) and adds them to the list of its instance items. The=
re is exactly one child item per template, and it is created automatically.=
 Note that this is analog to the way non-graphical classes operate.

Now look at another example: MineSweeper (I'm not sure whether you know tha=
t: It's a simple game that comes with Windows; it basically contains a grid=
 of identical small pushbuttons, each covering a "mine", that are arranged =
in a rectangular grid). It would be no fun to specify 400 identical instanc=
e items for a 20x20 grid. So my original idea was to have another outline s=
ection in the parent window that was meant to contain subitem templates tha=
t where NOT to be instantiated automatically like those in the dlgLogin exa=
mple, but programmatically to allow for repeated instantiation.
But, of course, one could write:

Window: dlgMineField
 ...
 Instance items:
  PushButton: pbMine []

... and simply declare an array of pbMine that would be filled at creation =
time.

>I assume you're defining properties to be constant here.  Hence a copy
>is unneeded and you can reuse the same object.  If you had properties
>that were not constant, eg the text font might change due to a checkbox
>somewhere else being chosen, you would not use that for a property but
>instead have both fonts as a "initial font" property and "changed font"
>property respectively.

Or, rather, "Arial" (ie template-specified) / "use ParentClass" (ie inherit=
ed from parent class) / "use parent window" (ie "inherited" from surroundin=
g window).

>Because a copy is unneeded you might keep a prototype repository where
>you pass the prototype id and get the prototype back which could be
>created lazily if desired or the whole lot could be loaded from a file
>or whatever.  This wouldn't require any extra language facility.
>
>You might want to keep the prototypes constant or the ability to change
>a lot of widgets at once might be useful.  But there is certainly a
>distinction between properties like font and transient properties like
>widget state.

Of course. For widget state, only the initial state would be set from the t=
emplate. But it would often be more sensible to set such states programmati=
cally, thus allowing to re-initialize them in the middle of the object's li=
fe time.

>It would be very difficult to merge these into one widget prototype if
>you actually had the message handler in the widget too.

Regarding message handlers, I should have been more specific:
What I'm calling "message handler" actually is just one _case_ inside the m=
essage handler (eg the reaction to message 12345). These cases need to be s=
pecified individually. MS-VC++ does it by ugly macros in the class that gen=
erate code for the message handler, like this:

	// Message Map
BEGIN_MSG_MAP(CExtSnapPPage)
	MESSAGE_HANDLER( WM_COMMAND, CommandHandler )
	MESSAGE_HANDLER( WM_NOTIFY, NotifyHandler)
	MESSAGE_HANDLER(PSM_QUERYSIBLINGS, QueryHandler)
END_MSG_MAP()

Such a macro has the disadvantage that it does not support automatic inheri=
tance.
If you need special code, you either put that into the (surrounding) toplev=
el window or <overkill> derive a whole new class </overkill>. Furthermore, =
it has the inconvenience that each subhandler (eg CommandHandler) needs a n=
ame and a declaration, which is unneccessary if it is called only from one =
place.

In Centura, the message handler body (ie the Big Switch) is completely invi=
sible to the programmer; all he sees are the indivudal subhandlers. (I woul=
dn't go that far, though, for flexibility reasons).

>>> So do these editors allow you to define a control that inherits the
>properties
>>> of another control?
>> Yes. Usually that will be the surrounding window.
>
>When you say "surrounding window" do you mean "surrounding widget" or do
>you mean it literally?

Not sure what you are asking here. I'll try to explain: Each non-toplevel w=
indow is a child window of some other window. Non-toplevel child windows sh=
own inside (on-top) the parent window's client area and are clipped by the =
parent window's borders. If the parent window is destroyed, so are all of i=
ts child windows. Child windows may be nested; all the conditions noted abo=
ve apply in this case as well. Thus, the parent window always is the (geome=
tricaly, border-wise) surrounding window of each of its non-toplevel child =
windows as well.

(Toplevel windows can be children of other toplevel windows, but that's a d=
ifferent affair).

>And if you could change these templates at run-time, would they be
>embedding or delegation based, ie would changes to the parents effect
>children that haven't overridden?  At the very least you'd need the
>ability to create your own templates based on other templates at
>run-time.

I reckon that changes to the parent should affect children that haven't ove=
rridden. Otherwise it could be done by an (automated?) edit-time copy. I'm =
not sure whether changes at run time would occur frequently, however.
Maybe both options could be present, like:
Specify here / Inherit from parent / Copy from parent

>> <Window: MyToplevelWindow    // type 1 item>
>>   Window Position            // type 3 item - you couldn't add this comm=
ent
>>    Top: <0                   // type 2 item>
>>    Left: <0>
>>    Widht: <400>
>>    Height: <300>
>>   Window Style
>>    Border? <true>
>>    System Menu? <true>
>>    ...
>
>I would expect this to be merely one view of the GUI languages of
>course.  A more graphical dragging and dropping alternative would be
>another.

Of course.

>> I would suggest to keep that editor-related stuff in a separate class to=
 be
>> able to easily strip it for a release version of the program.
>
>I would consider the "class" to be different in the sense of GUI
>Builders and HLLs.  GUI builders have an editor element which is
>actually a widget defined in the program/language library, whereas a HLL
>has an editor element which is a language element.

You mean GUI builders have a window painter where non-graphical "builders" =
have a text editor? Yes, but having text editing capability for the interna=
l (non-graphical) representation of GUI elements' properties is valuable as=
 well. And, given structured storage with self-description facilities, both=
 text editors can be unified. The graphical editor remains a separate entit=
y. Both are "views" operating on the same "document".

>I think this code should never be a part of the editor core since it's
>view-oriented.  The editor core would:
>
>o coordinate the shared UI (whatever that might be)
>o coordinate adding and removing languages, translations and views
>into/from the system
>o coordinate translations (ie incremental compilation)
>o coordinate views (ie ensuring changes made in one window are
>immediately reflected in others)

Basically yes. I'd also put in library code for the most common edit behavi=
ours and the tree view framework for the outline editor.

>> Sure. The editor somehow needs to know which instance items to treat as
>> properties. At first glance, I can think of several ways to do this:
>
>Maybe you could choose all public fields?

IMO programm access (public, ...) and being a property are orthogonal (thus=
 need to be specified independently). There is no point in displaying publi=
c items that do not need not have their initial state set at edit time (oth=
er than for debug purposes, that is).

Displaying all items can be a major waste of valuable screen space. If some=
one wants to include/exclude a specific item from the customisation structu=
red view, he/she can do so anyway by changing the item's definition. =


>> 1. Add a keyword (say, "property") to the instance item's declaration.
>>    Only usable for simple cases since no specific customisation info can=
 be
>>    presented this way.
>>    ...
>>    Writing a keyword is much less work than writing a whole class.
>>    ...
>
>I wouldn't say that this action is common enough to warrant introducing
>a new HLL feature on prototypes.  It's certainly useful for widgets and
>probably some other classes, but at least for widgets I doubt they're
>defined anywhere near as often as they're used.

In the meanwhile we got so many "features" or "properties" of *identifiers*=
 that we should think about having an identifier class. That would would al=
low for complete flexibility in defining things like "public", "transparent=
", "property" and it would slim down the *core* language description, expor=
ting those things to the definitions of specialized languages (which could =
inherit from each other).

>> All of the above ways silently include the assumption that there is only=
 one
>> such "customisation set" for each class. This might be sufficient in mos=
t
>cases,
>> but why should we accept that restriction right from the start?
>
>If you chose them all it wouldn't be a restriction.

Sure, but again, displaying all items could be a major waste of valuable sc=
reen space. =


>     Matthew Tuck - Software Developer & All-Round Nice Guy
>             mailto:matty@box.net.au (ICQ #8125618)
>       Check out the Ultra programming language project!
>              http://www.box.net.au/~matty/ultra/
>

--

Regards,

Hans-Dieter Dreier
(Hans-Dieter.Dreier@materna.de)=

--wF9BjfqF5aIGMkqIyBTlcsGcxqpDzE31
Content-type: text/plain; charset="ISO-8859-1"
Content-transfer-encoding: quoted-printable

IDENTIFIKATIONSANGABEN:
a19273a.txt IA5 DX-MAIL X.400 User Agent=

--wF9BjfqF5aIGMkqIyBTlcsGcxqpDzE31--