Subwindow Widgets in Omnis Studio (was: Displaying icons in a complex grid)
Bastiaan Olij
bastiaan at basenlily.me
Tue Mar 3 18:22:52 EST 2015
Hey Mischa,
On 4/03/2015 4:18 am, Mischa wrote:
> But what I want to induce is a common enhancement request to TL ;) - as also
> Bas points out very true in his reply - we don't need another 100 window
> components. What we really would need is a generic widget component, that is
> subwindow only, has customizable properties that show up in the property
> manager and can be inherited from superclasses. It also works within complex
> grids, and its dataname property is available already in the $construct
> method, and linked dynamically to the assigned variable. I know this is a
> lot, and maybe not doable in Studio - however it would reduce the need of
> new window components to a minimum.
The problem is that it breaks a fundamental principle on which window
controls are based and that is that they know nothing of the outside
world. None of the window components have any knowledge or direct access
to your variable. $dataname might be a property on your component, the
component itself is blissfully unaware and uncaring about its contents.
It's just there for the logic in the containing window to interact with.
When you have an entry field on a window it is actually not showing the
contents of your variable. Not directly anyway. It has a copy of the
data held internally. For convenience you can access this data through
the fields $contents property but internally it uses a more optimal
backdoor (when writing XCOMPS this is exposed through the primary data
window messages).
It is the parent windows responsibility to copy the contents of your
variable into the contents of your field when it has been changed (which
usually happens on a redraw) and copy the contents of your field back
into the variable when you've interacted with the field (which usually
happens on or just before the evAfter).
This is why, when you implement keyevents on an entry field, the
contents of your variable never changes, you have to interact with the
$content of your field to see how the keyboard action has changed your
contents.
If you would look at the code behind the scenes you would find something
in the C++source code that would be similar to implementing this in Omnis:
--------------------
wMyWindow.$redraw(bSetcontents,bRefresh,bBobjs)
---
if bSetContents
do
$cinst.$objs.$sendall($ref.$contents.$assign([$sendallref.$dataname]),
$ref.$contents <> [$ref.$dataname])
end if;
if bRefresh
do $cinst.$objs.$sendall($ref.$refresh(bSetcontents,bRefresh,bBobjs)
end if;
if bBobjs
do $cinst.$bobjs.$sendall($ref.$refresh())
end if;
wMyWindow.$eventhandler(bObjSendingEvent)
---
on evAfter
calculate [bObjSendingEvent.$dataname] as bObjSendingEvent.$contents
do bObjSendingEvent.$event()
--------------------
This last one looks a little weird but all events are routed through the
main windows message handler first and then directed to the correct
component on the window.
This is something that is very hidden to us Omnis developers and fairly
hidden in modern frameworks but pick up one of the early C or C++
programming guides for say Windows 95, or one of the first based on
Microsoft Foundation Classes and you would find data binding being
omitted completely. You the programmer had to write the code that copied
the contents of your variables into the fields that displayed them, and
you the programmer had to copy the contents of the field back into your
variable when the user had interacted with the field often having to do
numeric to character conversions and back yourself.
Many of the frameworks, Cocoa, later versions of MFC, etc. all started
to implement data binding in one way, shape or form so this has slowly
disappeared from view with one notable exception. HTML forms again do
not have any form of native databinding and thus in Javascript you now
find legions of different libraries that handle databinding for you.
What is immensely interesting to me is that Omnis Classic, while solving
databinding very differently from what I described above (it pre-dates
all this stuff), actually solved databinding in such an intuitive way we
Omnis developers don't even think about it, and it did so before many
others. It is one way Omnis was way ahead of its time and saved
countless of hours of development time. Even today I believe Omnis'
solution to the problem is way more elegant then what is offered by many
other IDEs.
To finish the sidetrack in Omnis Classic, because it is important for
the point I'm trying to make in regards to complex grids, table fields
in Classic where also unique. In Classic there was only one "instance"
of the entry field for your table field and the entry field was simply
drawn as many times as it appears on your screen each time with
different data for the different rows. The upside, way more effective
and faster. The downside? Components had to be written specifically with
table fields in mind which is why you were limited to the fields you
could use on table classes and they would sometimes behave differently
to their window counterparts.
Fast forward to Studio days this no longer applies. If you have a
complex grid showing a list with 1000 lines guess what, you have 1000
instances of entry fields each containing a copy of the data from the
row they are displaying.
Now extrapolate that if all those instances where subwindows.
It doesn't take much to understand what that does in terms of performance.
That all said, I still wouldn't mind if Omnis had a construct for
creating components within Omnis. Maybe a new class type that lets us
write the "paint" logic in a subset of Omnis code.
Cheers,
Bas
More information about the omnisdev-en
mailing list