QDialog::exec() starts its own event loop, independent of the main application's event loop. The loop is modal, meaning that events from other event loops are not processed until the dialog's loop exits. So your worker thread might be running, but the events it sends back to the parent process aren't handled until the dialog is closed.

A call to the static method QCoreApplication::processEvents() is the usual remedy to avoid the app freezing during long compute processes. This might work here, but I haven't studied your code in enough detail to know where to place it. Possibly in the slot that handles the finished status from the worker thread.