我对PyGTK很新,并且一直在尝试编写一个自动更新的图片幻灯片程序。到目前为止,它完全符合我的需要,但有一个问题。它通过在保存的目录中拍摄图像,然后在计时器上运行它们来运行。当它到达最后一张照片时,它应该重置并再次运行,这样您就可以随时添加新照片而不会停止它。它就是这样,但打开新窗口而不是正确重置。因此,如果它运行三次,则有三个窗口打开,它可以相当快地拉紧计算机。有没有人知道解决这个问题的方法?
代码相当冗长,但这里仅供参考:
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', '.gif']:
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 = 1
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
if self.index >= len(self.files):
self.index = 0
gtk.main_quit()
return self.display()
return self.display()
if __name__ == "__main__":
gui = DemoGtk()
gtk.main()
while True:
execfile("slideshowtest.py")
答案 0 :(得分:0)
出于您的目的,在self.load_file_list()
方法中执行gtk.main_quit()
而不是on_tick(self)
就足够了。
但是,我认为你的程序可以简化一点。这基本上是相同的,需要一半的代码行(它是PyGObject的,但可以更改为pygtk):
from gi.repository import Gtk, GdkPixbuf, GLib, Gdk
import sys, os
class ImageWindow(Gtk.Window):
def __init__(self, fullscreen=False, walk=True):
Gtk.Window.__init__(self, title="image test")
self.connect('delete-event', Gtk.main_quit)
if fullscreen:
self.fullscreen()
else:
self.set_default_size(500, 500)
self.walk = walk
self.files = []
self.image = Gtk.Image()
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(self.image)
scrolled_window.override_background_color(
Gtk.StateFlags.NORMAL,
Gdk.RGBA(red=0, blue=0, green=0)
)
self.add(scrolled_window)
self.load_image()
self.connect('check-resize', self.on_resize)
GLib.timeout_add_seconds(3, self.load_image)
def on_resize(self, window):
width, height = self.get_size()
self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.current_file)
if float(width) / height > self.dimension:
self.pixbuf = self.pixbuf.scale_simple(
self.dimension * height,
height,
GdkPixbuf.InterpType.NEAREST
)
else:
self.pixbuf = self.pixbuf.scale_simple(
width,
width / self.dimension,
GdkPixbuf.InterpType.NEAREST
)
GLib.idle_add(self.image.set_from_pixbuf, self.pixbuf)
def load_image(self):
if len(self.files) == 0:
self.get_images()
self.current_file = self.files.pop()
self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.current_file)
self.image.set_from_pixbuf(self.pixbuf)
width = self.pixbuf.get_width()
height = self.pixbuf.get_height()
self.dimension = float(width) / height
return True
def get_images(self):
if self.walk:
for directory, sub_directories, files in os.walk('.'):
for filename in files:
if self.is_image(filename):
filepath = os.path.join(directory, filename)
self.files.append(filepath)
else:
for filename in os.listdir('.'):
if self.is_image(filename):
self.files.append(filename)
print('Images: {}'.format(self.files))
def is_image(self, filename):
return filename.split('.')[-1].lower() in ['png', 'jpg', 'gif']
if __name__ == '__main__':
win = ImageWindow()
win.show_all()
Gtk.main()