PyGTK:如何使图像自动缩放以适应其父组件?
我有一个用PyGTK做的应用程序,需要加载一个大小不确定的图片。不过,我遇到了一个问题:如果图片太大或者太小,窗口的布局就会变得很乱,使用起来很不方便。我需要一种方法,让图片能够自动缩放,以适应它的父控件。不幸的是,经过一些研究,我发现似乎没有现成的代码可以实现我想要的效果。
我该怎么写代码来实现这个功能呢?我本以为应该有人已经写过这样的代码;难道我漏掉了什么吗?
3 个回答
0
这里有一个简单的代码片段,它可以让你使用自动缩放的图片。
import gtk
class ImageEx(gtk.Image):
pixbuf = None
def __init__(self, *args, **kwargs):
super(ImageEx, self).__init__(*args, **kwargs)
self.connect("size-allocate", self.on_size_allocate)
def set_pixbuf(self, pixbuf):
"""
use this function instead set_from_pixbuf
it sets additional pixbuf, which allows to implement autoscaling
"""
self.pixbuf = pixbuf
self.set_from_pixbuf(pixbuf)
def on_size_allocate(self, obj, rect):
# skip if no pixbuf set
if self.pixbuf is None:
return
# calculate proportions for image widget and for image
k_pixbuf = float(self.pixbuf.props.height) / self.pixbuf.props.width
k_rect = float(rect.height) / rect.width
# recalculate new height and width
if k_pixbuf < k_rect:
newWidth = rect.width
newHeight = int(newWidth * k_pixbuf)
else:
newHeight = rect.height
newWidth = int(newHeight / k_pixbuf)
# get internal image pixbuf and check that it not yet have new sizes
# that's allow us to avoid endless size_allocate cycle
base_pixbuf = self.get_pixbuf()
if base_pixbuf.props.height == newHeight and base_pixbuf.props.width == newWidth:
return
# scale image
base_pixbuf = self.pixbuf.scale_simple(
newWidth,
newHeight,
gtk.gdk.INTERP_BILINEAR
)
# set internal image pixbuf to scaled image
self.set_from_pixbuf(base_pixbuf)
下面是一个小的使用示例:
class MainWindow(object):
def __init__(self):
self.window = gtk.Window()
self.window.connect("destroy", gtk.main_quit)
# create new ImageEx
self.image = ImageEx()
# set size request, to limit image size
self.image.set_size_request(width=400, height=400)
# load image from file, change path with path of some of your image
pixbuf = gtk.gdk.pixbuf_new_from_file("path/to/your/image.jpeg")
# that's the key moment, instead `set_from_pixbuf` function
# we use our newly created set_pixbuf, which do some additional assignments
self.image.set_pixbuf(pixbuf)
# add widget and show window
self.window.add(self.image)
self.window.show_all()
if __name__ == '__main__':
MainWindow()
gtk.main()
1
这里有一段代码,可以在绘图区域完成这个任务:
self.spash_pixbuf = GdkPixbuf.Pixbuf.new_from_file('myfile.png')
...
def on_draw(self, widget, cairo_ct):
"""
draw
"""
self._cairo_ct = cairo_ct
self._width = widget.get_allocated_width()
self._height = widget.get_allocated_height()
self._draw_cover(self.spash_pixbuf)
def _draw_cover(self, pixbuf):
"""
Paint pixbuf to cover drawingarea.
"""
img_width = float(pixbuf.get_width())
img_height = float(pixbuf.get_height())
# Scale
width_ratio = self._width / img_width
height_ratio = self._height / img_height
scale_xy = max(height_ratio, width_ratio)
# Center
off_x = (self._width - round(img_width*scale_xy)) //2
off_y = (self._height - round(img_height*scale_xy)) //2
# Paint
self._cairo_ct.save()
self._cairo_ct.translate(off_x, off_y)
self._cairo_ct.scale(scale_xy, scale_xy)
Gdk.cairo_set_source_pixbuf(self._cairo_ct, pixbuf, 0, 0)
self._cairo_ct.paint()
self._cairo_ct.restore()
10
你可以使用 widget.get_allocation() 来获取父组件的大小,然后用 pixbuf.scale_simple 来调整图片的大小,像这样:
allocation = parent_widget.get_allocation()
desired_width = allocation.width
desired_height = allocation.height
pixbuf = gtk.gdk.pixbuf_new_from_file('your_image.png')
pixbuf = pixbuf.scale_simple(desired_width, desired_height, gtk.gdk.INTERP_BILINEAR)
image = gtk.image_new_from_pixbuf(pixbuf)
如果你希望每次窗口调整大小时,图片也能跟着调整,那你需要把上面的代码(或者类似的代码,以避免每次都从磁盘加载图片)放在一个函数里,这个函数要和父组件的 size_allocate 信号连接起来。为了避免出现无限循环,确保你放在组件里的图片不会再次改变它的大小。
参考资料:
- 如何调整图片大小(我想你已经看过这个了)
- 关于“调整大小”事件
- Stack Overflow 上关于调整大小的其他链接