I want to start some things as soon as the main window (defaultWindows) has finished loading and all objects are drawn. I could start a timer and wait some ticks on average but there must be a better way in accomplice this?
Use the Activate event. You’ll need a guard variable so your code will only be called the first time the Activate event fires, which is immediately after the Open event.
In the Open event:
firstTime = True
In the Activate event:
If firstTime Then
firstTime = False
// do something directly after the Open event
// do something each time the Activate event fires
I have been using RB/Xojo for 13 years and since day 1 I have seem admonitions from the engineers to not rely on order of events. That’s why I think your current practice of using a short period timer to fire your procedures after the screen has finished loading is the best one.
The Window open event is guaranteed to fire after the open events of all the controls on the window… That is not good enough?
No, I noticed that the Open event fires before all objects are painted. I want to make sure that all objects are visible, then start my method. That is certainly not the case.
Desktop or web app ?
OK, let me rephrase my statement. I have this Win7 application, consisting of one Window and one Listbox and a few buttons.
In the Open event of the Listbox I read a database, rather large, into the listbox (7000 records, 1.6 GB). The reading of the records is done in a thread with normal parameters.
If I understand things correctly what would happen is that the windows loads, the listbox opens and the thread starts running. Meanwhile I expect the window to become visible… but that doesn’t happen. I don’t see a task bar item either. The window gets visible once the thread is finished… That doesn’t make sense because the database thread should allow the main thread to execute normal, that is in a time slice fashion.
First you can’t modify the UI from a thread, so is the thread just reading the records into memory? I assume so. Either that or the code is executing on the main event loop
I don’t use threads but it sounds like the the thread is not yielding time to the main event loop that handles drawing the UI.
The listbox open event happens before the Window.Open event and so before the Window drawing occurs .
OK, as far as I’m concerned I do not update the UI… just loading a Listbox with addrow().
To keep the user informed I update a Progress bar but from within a timer event (like in the documentation).
The Listbox should just show the added rows, but as you said it happens before the Window drawing occurs, so there is no visible update. I can understand that, though the usage of a thread should avoid this.
I tried some other testing:
dim I as integer
for i = 0 to 100000
Listbox1.addrow("This is row: " + str(i))
You say that you cannot modify the UI from within a thread but that’s exactly what’s happening here (if you can call loading a listbox a UI update, I guess so).
In this thread the Listbox get’s filled (you see the scrollbar reacting), the listbox is responsive and no problems arise. I execute this form within a Button.Action event, so the UI is loaded already.
[quote]Updating the User Interface from a Thread
NOTE: Do not access any built-in property or method of a user interface control or Window from within a Thread. Doing so raises a ThreadAccessingUIException. See below for additional information.
I read that part over and over again…
Ok… you DON’T get that exception in Windows but do on OSX … i wonder if that is a bug!!! Beware of that if you also target OSX!!!
BTW your examples works instantly on Win 7 for me
Now I think is that the DB access is not yielding and is what is delaying things
Thats updating the UI
Ok, got it, thanks.
the database is SQlite and very repsonsive, is on the same machine and as soon as the listbox is filled there is no delay when retrieving data. The database contains (MS Office) files and they are read split-second if I want to bring one up.
What would be in your opinion the best way in reading this database and populating a listbox as first thing after the app is loaded?
Only if your thread yields enough time to allow the main thread to execute. RB used to lean towards yielding more time by default. That allowed most threads to function “normally” (read: not impinge on the UI). That changed some time back to leaning toward giving more time to the thread and yielding less. That’s a good thing, but it means you have to do some extra work to keep the UI responsive.
Which operation takes all the time?
a) the SQLSelect statement?
b) the loop that populates the listbox?
If a), then see Karen’s link to ThreadYieldInterval.
If b), then put the loop into a timer instead of a thread and load N records each time it fires. Adjust N to balance throughput vs responsiveness.
[quote=29629:@Tim Hare]b) the loop that populates the listbox?
it’s not that… I loaded 10,000 rows into a listbox from a thread initiated in listbox.open without it blocking the UI on Windows 7
But are you pulling 1.6GB out of a database during that loop? It may be the select, or it may be the cumulative effect of actually reading the data. We don’t know for sure without him telling us.
[quote=29633:@Tim Hare]But are you pulling 1.6GB out of a database during that loop? It may be the select, or it may be the cumulative effect of actually reading the data. We don’t know for sure without him telling us.
If it is the select, then ThreadYieldInterval should fix it, no?