I've read the following answers already on SE, but I cannot yet seem to replicate the end result I need in Blender 2.71.
- https://stackoverflow.com/questions/13485720/blender-python-scripting-trying-to-prevent-ui-lock-up-while-doing-large-calcula/16744008#16744008
- Blender not responding while running my script
- Blender UI Multithreading Progressbar
I'm running a panel script that uses an operator button to download a file from an external URL. I've not yet found a way to do this without blocking the UI.
I've tested modal operators and used multithreading, no luck yet. Can anyone demonstrate that this is actually possible?
If it is possible, I would then use a modal operator timer to check on the progress and update a label in the ui panel.
Here's my attempt via a modal operator timer similar to the first link in the list.
import bpy
import sys
import urllib
from urllib import request
from urllib.request import urlretrieve
def reporthook(blocknum, blocksize, totalsize):
readsofar = blocknum * blocksize
if totalsize > 0:
percent = readsofar * 1e2 / totalsize
s = "\r%5.1f%% %*d / %d" % (percent, len(str(totalsize)), readsofar, totalsize)
sys.stderr.write(s)
if readsofar >= totalsize: # near the end
sys.stderr.write("\n")
else: # total size is unknown
sys.stderr.write("read %d\n" % (readsofar,))
class ModalTimerOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.modal_timer_operator"
bl_label = "Modal Timer Operator"
_timer = None
_updating = False
_download_done = False
def do_download(self):
print("starting file download")
#actual url and local path removed for privacy
urlretrieve("REMOTE_URL", "LOCAL_DEST", reporthook)
self._download_done = True
def modal(self, context, event):
if event.type == 'TIMER' and not self._updating:
self._updating = True
self.do_download()
self._updating = False
if self._download_done:
self.cancel(context)
return {'PASS_THROUGH'}
def execute(self, context):
wm = context.window_manager
self._timer = wm.event_timer_add(2, context.window)
wm.modal_handler_add(self)
self._updating = False
return {'RUNNING_MODAL'}
def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
def register():
bpy.utils.register_class(ModalTimerOperator)
def unregister():
bpy.utils.unregister_class(ModalTimerOperator)
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
bpy.ops.wm.modal_timer_operator()