python - Running Tkinter dependent code alongside mainloop without GUI freeze -


i writing simple image viewer lets user flip through tens of thousands of images, 100 @ time. images files on disk.

in order viewer function, must continuously preload images ahead of user's current 1 (or viewer unusably sluggish).

the basic recipe i'm using display images in grid of tkinter labels, following (this has been tested , works):

def load_image(fn):     image = image.open(fn)     print "before photoimage"     img = imagetk.photoimage(image)     print "after photoimage"  label.config(image=load_image("some_image.png") 

i need imagetk.photoimage instance display image on label. have implemented 2 different approaches, each associated problem.

first approach: launch separate thread pre-loads images:

def load_ahead():     fn in images:         cache[fn] = load_image() threading.thread(target=load_ahead).start() top.mainloop() 

this works quite on linux machine. however, on machine (which happens running windows, , compiled pyinstaller), deadlock seems happen. "before photoimage" printed, , program freezes, suggests loader thread gets stuck @ creating imagetk.photoimage object. musst creation of imagetk.photoimage object happen within main (tkinter mainloop's) thread? creation of photoimage computationally expensive, or negligible compared loading image disk?

second approach: in order circumvent possible requirement of photoimage objects being created within tkiner's mainloop thread, resorted tk.after:

def load_some_images():     #load 10 images. function must return prevent freezing gui     in xrange(10):          fn = get_next_image()         cache[fn] = load_image(fn)     top.after_idle(load_some_images)  top.after_idle(load_some_images) 

the problem that, appart creating additional overhead (ie image-loading procedure must broken small chunks since competing gui) periodically freezes gui duration of call, , seems consume keyboard events happened during execution.

third approach there way can detect pending user events? how can accomplish this?

def load_some_images():     while true:         try: top.pending_gui_events.get_nowait()         except: break         #user still idle! continuing caching of images         fn = get_next_image()         cache[fn] = load_image(fn)     top.after_idle(load_some_images)  top.after(5,load_some_images) 

edit: have tried using top.tk.call('after','info') check pending keyboard events. doesn't reliably, , interface still sluggish/unresponsive.

thanks in advance ideas

i recommend creating load_one_image function rather load_some_images function. less interfere event loop.

also, rule of thumb, function called via after_idle shouldn't reschedule self after_idle. reason after_idle block until idle event queue drained. if keep adding stuff on queue while queue being processed, never gets drained. reason why gui seems hang once in while second approach.

try after(5, ...) rather after_idle(...). if system can create image in less 5ms, can process 100 images in half second, fast enough give pretty snappy interface. can tweak delay see how affects overall feel of app.


Comments

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -