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--