[Gambas-user] A Gambas odissey

Doriano Blengino 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:

  ME.MoveTo(path)
  DO
    IF ME.movechild() THEN BREAK
    ME.Item.Delete
    ME.MoveTo(path)
  LOOP

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:

  DO
    ME.MoveTo(path)
    IF ME.movechild() THEN BREAK
    ME.Item.Delete
  LOOP


>> 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 
CPU... :-))
So, "I raise an event" should mean "the object we are talking of raises 
an event"...

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 
Shortcut.
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...
Just joking...

>> 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.
>
> http://gambasdoc.org/help/doc/object-model
> http://gambasdoc.org/help/cat/event
> http://gambasdoc.org/help/comp/gb/observer
>   
Ok, I read them. The docs do not go deep enough for the speaking we are 
making now.
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 
"flexible".
Looking at DirView source, I see:

  $bNoEvent = TRUE
  $hTreeView.Clear
  ...
  TreeView_Expand
  $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 
appropriate).
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 mailing list