[Gambas-user] A Gambas odissey
doriano.blengino at ...1909...
Wed Aug 13 17:40:26 CEST 2008
Benoit Minisini ha scritto:
>> I failed,
>> instead, in removing all the children of an item, one by one (there is a
>> clear() method, but I need to delete them one by one). The "for each ...
>> in item.children" does not work; it is not the first time I see similar
>> anomalies, especially while stepping the source.
> Items are not enumerable, because they are not true objects.
> Instead, you must use the Move* methods that move an internal cursor. Use the
> TreeView.Item property to get the item pointed by that internal cursor.
Sorry - it was my mistake. Actually I didn't use "for each", but this:
IF ME.movechild() THEN BREAK
The idea is to delete children of Path, one by one. It is this example
that does not work, it even dirties the string variable Path. I noticed
that stepping the source sometimes has unwanted side effects, which
disappear when the program is run normally. And, I see now that it can
be written as:
IF ME.movechild() THEN BREAK
>> Writing MyDirView revealed another problem. If in a custom control I
>> receive the KeyPress event, I can not re-raise it (stack overflow).
> If "you" (I think "you" mean "an object A") receives an event from an
> object "B", raising it "again" does not mean anything. Only the object "B"
> can raise the event again.
> If you mean that the object A is its own event observer, why would it need to
> send itself an event?
When writing code, I project myself into the code and think as I was the
So, "I raise an event" should mean "the object we are talking of raises
And about sending events to itself... why not? Often I set up a timer
only to posticipate an action (note: *not* to delay it, only to get out
the event handler). For example, I had a problem with deleting a
TabStrip from a Button inside it. The TabStrip refused to Delete()
because it was not empty; so in the event handler of the Button I set up
a timer which, in the next event loop, deletes the TabStrip.
The purpose of the timer is not to delay things, but to posticipate
them. It is a mean to send an event to itself.
> FileView and DirView are compound controls, they do not inherit TreeView or
> whatever directly. This is mandatory for the FileView control, as it has
> actually two different views inside: a ListView and an IconView.
> You don't see KeyPress event sent by the inside views, for the same reason a
> Container does not see the KeyPress events sent by its children.
> I admit this seems a bit stupid from the outside.
I don't understand why DirView does not inherit from TreeView. I looked
at the source, and there is nothing that prevents that.
A DirView is no less than a TreeView; simply, its items are directory
names. A routine to read directory names from file system and put them
in the tree could be the only different thing.
Look at my file manager application, in the MyDirView class. The only
routine which has to do with files is populate(). All the rest is there
because of missing things in TreeView, or because I am not a good
programmer, or because I am not a good documentation reader.
>> I don't want to rewrite MyFileView
>> just now (I will do, because I need more functionalities). I only need
>> to catch Backspace and Enter, so I make a menu voice
> A menu "voice"? What's that?
A menu item, an object of type Menu, which has a Name, a Caption, a
Sorry for my naming confusion.
> Application.ActiveControl will tell you.
Aaahhhh! Look at http://gambasdoc.org/help/comp/gb/application
Just speaking of Delphi, the Oracle of Delphi would help in such
cases... if you can not find something in the docs, ask the Oracle...
>> Delphi forms have a KeyPreview property. If you set it, then *all* the
>> keypresses are first passed to the form. The form then decides wether to
>> ignore the key, or make additional things, to let the key pass, or to
>> stop it.
> I think this is possible to implement.
There are situations where it can help.
>> Moreover, every control has a Focused property
>> which tells if a specific control has the focus or not.
> I can implement that too. Maybe I will call it "HasFocus" instead.
To avoid to write duplicates, could be better think twice. Having
Application.ActiveControl already covers this case, perhaps:
if Application.ActiveControl = ControlToTestForFocus then ...
>> Finally, I must say that I think, and *repeat*, I think, the event
>> management is wrong or, at least, it is not as flexible as it could be.
>> Once a control raises event, you can not make it stop. If you group
>> controls, you group all their events. Once you assign a handler to an
>> event, you can no more change it.
> Mmm. Not really. Maybe you should first understand that it works differently
> in Gambas than in Delphi.
Ok, I read them. The docs do not go deep enough for the speaking we are
I learned that, with Object.lock(), you can stop a control to send
events. I did not know. Problem is, you disable *all* its events.
With Object.Attach() you can change the event names of a control (all
the events), not a single event handler.
A group of controls can share events - yes: all the events or none of them.
You see, and please take this with friendship, this is not what I call
Looking at DirView source, I see:
$bNoEvent = TRUE
$bNoEvent = FALSE
This is a clear symptom of lack of flexibility. You have to circumvent
the normal event processing, because it is not flexible enough.
To solve this problem, you had:
- to declare a variable ($bNoEvent) somewhere in the outer scope
- to set/reset that variable (and this is required, because in some
point you want to stop the events)
- to modify the relevant event handler and make it test $bNoEvent
In delphi, the same thing would have reduced to set/reset the
TreeView.OnSelect property, i.e., exactly the only thing we wanted.
Anyway, this particular case is not important - I solved already similar
cases as you did in DirView.
But, please, don't tell me I say this because I am used to delphi and
not to Gambas. This is true only in part...
> You are mixing again the object that raises the event with the object that
> receives it. Apparently, this concept does not exist in Delphi, or it is not
> clearly visible. Not really object-oriented... :-)
Ah ah ah...
Please, please, please... give delphi a try, so you will speak knowing
what you are saying.
In this discussion, I win 1,5 to 1, because I know delphi and a little
gambas, you keep saying you don't know delphi. It is true that you know
gambas better than me (and better than everyone else, right?), so may be
I win only 1,5 to 1,4...
Objects and events are two concepts totally unrelated. Tcl/Tk has event
management, and it is not an object language. Turbo pascal was a true
object language, and had no events.
You say half the truth in saying that the event concept is not clearly
visible in delphi. This comes from the fact that delphi is strictly
bound to the windows world, where events are called "messages". Delphi
manages them perfectly, but they are not the best. The power of delphi
is such it can hide this awful thing behind "standard", strong-type
checked, parametrized function calls. Excuse me if this is not enough.
Messages in windows are records (structs in C), having 4 integers in
them. The first integer says what kind of message is, all the rest
depends on what type of message you look at. Those integers can contain
coordinates, key codes, or be pointers to some string in memory, or even
point to some complicated structure (which possibly you have to free,
once used...). These integers sometime are break in words, just for fun.
These messages are sent to the main procedure of a program, directed to
a window handle (in windows, everything is a window). This "WindowProc"
parses that record, and dispatches them to the appropriate window. So,
for a MouseDown event you receive a wonderful:
procedure TForm1.ListBox1MouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer);
which has in the header all the information you need, without going to
see key.xxx, mouse.xxx (external, unrelated variables).
You can not get the "no event data error", in delphi.
The LAST variable used in gambas, here is named Sender (the name is more
Beside the fact that this method is cleaner than in gambas, there is
another advantage: you can call/invoke event handlers as they were
normal subroutines (and they are in fact). You can not do it in gambas,
because the global variables LAST, Key, Mouse are undefined.
This also means that you don't need to raise events - you can invoke
directly the event handler, if you want. But, for the sake of
completeness, I must say that, if you want, you can send messages, and
you can send them in two different ways - normal way, or "post" them,
which means they are queued and processed in the next event loop. There
is also an Idle event, which is missing in gambas (apropos: how about to
implement it?). This event is raised when the application is idle -
useful for background processing.
Delphi is a true object/class language. Gambas is not. How about method
overriding, virtual methods, protected methods, default properties,
published properties, and the list could continue... but probably this
things are unknown for a visual basic programmer (fortunately you know
also C++. How events work in C++?).
Back on your half truth. Events, as known in gambas, do not exist in
delphi. They are simply not needed but, if you want to interface
directly with that monster called windows, then you can use messages
(which are events).
Want to know? Gambas events could be better if they had an associated
property to set. Grouping, disabling, intercepting, all this things
could be done. Gambas events could be better if they carried event
informations along: the pressed key for a keypress, the coordinates,
button and shift state for mousedown, and so on. Why gambas does it not?
Please tell me.
Ok, I am making all the people waste time.
I love gambas, and could love it more. This is all I have to say.
Nice day to everybody.
More information about the User