JimmyJohns
JimmyJohns

Reputation: 13

Any way to make a Python GTK window quit automatically?

I'm writing a code that I would like to repeat automatically, and for the most part I have it. If I use a while loop I can get it to repeat, but I have to close the window automatically for it to work. Is there any way I can get it to close by itself? The program is a slideshow. Code wise, the loop I'm using looks like this:

while True:
    execfile("slideshowtest.py")

If you need the rest of the code it looks like this:

import os

import pygtk
pygtk.require('2.0')
import gtk
import glib

def is_image(filename):
   if not os.path.isfile(filename):
    return False
for suffix in ['.jpg', '.png', '.bmp']:
    if filename.lower().endswith(suffix):
        return True
return False

def resizeToFit(image, frame, aspect=True, enlarge=False):
if aspect:
    return scaleToFit(image, frame, enlarge)
else:
    return stretchToFit(image, frame, enlarge)

def scaleToFit(image, frame, enlarge=False):
image_width, image_height = image
frame_width, frame_height = frame
image_aspect = float(image_width) / image_height
frame_aspect = float(frame_width) / frame_height
if not enlarge:
    max_width = min(frame_width, image_width)
    max_height = min(frame_height, image_height)
else:
    max_width = frame_width
    max_height = frame_height
if frame_aspect > image_aspect:
    height = max_height
    width = int(height * image_aspect)
else:
    width = max_width
    height = int(width / image_aspect)
return (width, height)

def stretchToFit(image, frame, enlarge=False):
image_width, image_height = image
frame_width, frame_height = frame
if not enlarge:
    width = min(frame_width, image_width)
    height = min(frame_height, image_height)
else:
    width = frame_width
    height = frame_height
return (width, height)


class ResizableImage(gtk.DrawingArea):

def __init__(self, aspect=True, enlarge=False,
        interp=gtk.gdk.INTERP_NEAREST, backcolor=None, max=(1600,1200)):
    super(ResizableImage, self).__init__()
    self.pixbuf = None
    self.aspect = aspect
    self.enlarge = enlarge
    self.interp = interp
    self.backcolor = backcolor
    self.max = max
    self.connect('expose_event', self.expose)
    self.connect('realize', self.on_realize)

def on_realize(self, widget):
    if self.backcolor is None:
        color = gtk.gdk.Color()
    else:
        color = gtk.gdk.Color(*self.backcolor)
    self.window.set_background(color)

def expose(self, widget, event):
    self.context = self.window.cairo_create()
    self.context.rectangle(
        event.area.x, event.area.y,
        event.area.width, event.area.height)
    self.context.clip()
    self.draw(self.context)
    return False

def draw(self, context):
    rect = self.get_allocation()
    x, y = rect.x, rect.y
    parent = self.get_parent()
    if parent:
        offset = parent.get_allocation()
        x -= offset.x
        y -= offset.y
    if self.backcolor:
        context.rectangle(x, y, rect.width, rect.height)
        context.set_source_rgb(*self.backcolor)
        context.fill_preserve()
    if not self.pixbuf:
        return
    width, height = resizeToFit(
        (self.pixbuf.get_width(), self.pixbuf.get_height()),
        (rect.width, rect.height),
        self.aspect,
        self.enlarge)
    x = x + (rect.width - width) / 2
    y = y + (rect.height - height) / 2
    context.set_source_pixbuf(
        self.pixbuf.scale_simple(width, height, self.interp), x, y)
    context.paint()

def set_from_pixbuf(self, pixbuf):
    width, height = pixbuf.get_width(), pixbuf.get_height()
    if not self.max or (width < self.max[0] and height < self.max[1]):
        self.pixbuf = pixbuf
    else:
        width, height = resizeToFit((width, height), self.max)
        self.pixbuf = pixbuf.scale_simple(
            width, height,
            gtk.gdk.INTERP_BILINEAR)
    self.invalidate()

def set_from_file(self, filename):
    self.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(filename))

def invalidate(self):
    self.queue_draw()

class DemoGtk:

SECONDS_BETWEEN_PICTURES = 2
FULLSCREEN = True
WALK_INSTEAD_LISTDIR = True

def __init__(self):
    self.window = gtk.Window()
    self.window.connect('destroy', gtk.main_quit)
    self.window.set_title('Slideshow')
    self.image = ResizableImage( True, True, gtk.gdk.INTERP_BILINEAR)
    self.image.show()
    self.window.add(self.image)
    self.load_file_list()
    self.window.show_all()
    if self.FULLSCREEN:
        self.window.fullscreen()
    glib.timeout_add_seconds(self.SECONDS_BETWEEN_PICTURES, self.on_tick)
    self.display()

def load_file_list(self):
    self.files = []
    self.index = 0
    if self.WALK_INSTEAD_LISTDIR:
        for directory, sub_directories, files in os.walk('.'):
            for filename in files:
                if is_image(filename):
                    filepath = os.path.join(directory, filename)
                    self.files.append(filepath)
    else:
        for filename in os.listdir('.'):
            if is_image(filename):
                self.files.append(filename)
    print "Images:", self.files

def display(self):
    if 0 <= self.index < len(self.files):
        self.image.set_from_file(self.files[self.index])
        return True
    else:
        return False

def on_tick(self):
    self.index += 1

    return self.display()
if __name__ == "__main__":
gui = DemoGtk()
gtk.main()

while True:
execfile("slideshowtest.py")

Upvotes: 1

Views: 1081

Answers (2)

crazydiv
crazydiv

Reputation: 842

Extending Ivan's answer, I needed window to close automatically after a couple of seconds. I ended up with something similar.

import threading
import time
def thread_function(name):
    time.sleep(DISPLAY_TIME)
    Gtk.main_quit()
x = threading.Thread(target=thread_function, args=(1,))
x.start() # Start thread and let thread sleep for N seconds

Gtk.main() # Start main Gtk

x.join() 

Upvotes: 1

ivan_pozdeev
ivan_pozdeev

Reputation: 35986

gtk Functions:

The gtk.main() function runs the main loop until the gtk.main_quit() function is called.

So you need to run your while loop in a separate thread and call main_quit() when you're finished.

Upvotes: 3

Related Questions