A more general and proper approach is to use message passing from std.concurrency. With DFL it looks like this: you spawn() a thread and don't pass any GUI controls to it, just thisTid (identifier of your main UI thread). In that worker tread when you've got some data to show in the UI (be it end result of just some status update) you use tid.send(...) and send the data in appropriate messages (defined as separate structs or classes). In the main UI thread you've got a Timer running that checks whether there are any messages in the main thread's mailbox and process them there.

Here's an example from a real DFL project:
https://bitbucket.org/infognition/undup/src/e8d295b89bc76545860e38a8c9ee171c86f3c84c/newscan.d?at=default#cl-200

OnStart() is a button callback. It does some quick UI updates and spawns a thread, passing relevant data and thisTid:

  worker = spawn(&makeScan, fname, hdr, thisTid);

(makeScan is a function with some long running operation, it's defined in another module)

There is also a timer set up when a form is created, and in the timer function OnTimer() there is a check for new messages via receiveTimeout(dur!"msecs"(0).

while(receiveTimeout(dur!"msecs"(0), &RcvMsgNumOfDirs, &RcvMsgScanning, &RcvMsgDone)) {}

Important part here is to make it non-blocking, it should not sit here waiting for new messages, otherwise UI will not be responsive.

And RcvMsgNumOfDirs, RcvMsgScanning, RcvMsgDone are functions that react to corresponding messages sent from the worker thread. They work in the UI thread, of course.

Reply via email to