We could use some sample code here, but here is some general pointers:
For functions which take a long time to process there are a few ways of doing it. You found the two obvious ones, namely let it run and thus block the interface, second start a thread and let that do the work. A third option to consider is to break up the work in smaller bits, thus in your idle loop calculate some of the work required, short enough so that the interface does not block and then return the control to the interface. In many cases, this is the simplest option.
But if you really want threads, then make you gui the primary thread and when one of your actions starts running, give it a shared variable (
threads::shared) so that it can report back progress, which you can then check in the idle loop.
T
I
M
T
O
W
T
D
I