[Gambas-user] Me.Close not working as expected
tobs at taboege.de
Thu Jul 1 20:01:43 CEST 2021
On Thu, 01 Jul 2021, Charlie Ogier wrote:
> Can you try this code and see if you experience my problem. The program
> should end on clicking the button, but it doesn't close until the end of the
> Button1 As Button
> Public Sub Button1_Click()
> Dim iLoop As Integer
> Me.Close '' Shouldn't the program stop here?
> For iLoop = 0 To 1000
> Print Str(iLoop) & " Hello"
> ***End code***
It happens on my Gambas, too. Let me give you an explanation of why I think
this is the expected behavior, on top of the practical advice by the others.
I think what happens is the following. You call the Close method on a Window
object. Gambas delegates this to the underlying GUI toolkit. In the case of
gb.qt5, apparently this sends a close event to the QT window object. Now,
Gambas installs a QT event handler for this close event. This is necessary
to support the Form_Close event on the Gambas level. The window cannot be
closed before the Gambas programmer had a chance to react to the Close event
in Gambas. Thus, it is necessary that the window does not close immediately.
gb.qt5 posts the Form_Close event to the event queue of Gambas. The event
is *not* raised immediately from there, but only when you next enter the
Gambas event loop. This does not happen from native C++ code and it does
not happen either when passing between Gambas and native code. So, the
window is kept alive for yet a little longer. Namely until your current
event handler, Button1_Click, finished executing. This is why you see the
result of the Print statements.
We have this chain of events:
--> Me.Close() is executed
--> gb.qt5 closes the window
--> close is intercepted by gb.qt5
--> Form_Close event is posted
--> gb.qt5 call returns
--> rest of Button1_Click code is executed
--> after Click event is processed, event loop is re-entered
Form_Close is processed
Window can be finally closed and program terminates
This all has to do with certain guarantees Gambas makes (not sure if they
are documented though) about processing events and at which points it is
considered safe to re-enter the event loop. Even though the Gambas inter-
preter is a single-threaded application, recursively entering the event
loop is a kind of parallelism, which most Gambas code and Gambas components
are not prepared to handle. Most Gambas code is not "reentrant" and you
should be thankful that you don't have to worry about that, usually.
As a rule of thumb, events are only processed when you are not currently
running code from an event handler or when you ask for it explicitly by
using the Wait instruction.
Let me give you an example of what I mean by "it is too unsafe to run the
event loop from a native component". Suppose a native component (or any
component, really) has a function F which you can call to do something
meaningful and which does re-enter the event loop. Suppose you are in a
Socket_Read() event -- some data arrived on your socket. You call the
function F because your program requires its functionality. It re-enters
the event loop. But you haven't read all the data of your socket yet,
so the Socket_Read event fires again, which causes your event handler
to recurse into F, fire the Socket_Read event again... Within a second,
the function call stack is exhausted and your program crashes with a
Note that even if you did read all the data in the socket before calling
F in this example, more data might have arrived in the meantime. This new
data is now processed before you unwind back to the original data. Thus
you end up processing the data in the wrong order! Writing programs which
are reentrant is hard. Be happy that Gambas doesn't make you do it.
Finally, my advice would be to use
if you want the closing to take place as soon as possible.
"There's an old saying: Don't change anything... ever!" -- Mr. Monk
More information about the User