【问题标题】:PyGTK: How do I make an image automatically scale to fit its parent widget?PyGTK:如何使图像自动缩放以适合其父小部件?
【发布时间】:2020-10-03 02:04:51
【问题描述】:

我有一个 PyGTK 应用程序需要加载未知大小的图像,但是我遇到的问题是,如果图像非常大或非常小,窗口布局会变得扭曲且难以使用。我需要某种方法使图像自动缩放以适合其父小部件。不幸的是,在做了一些研究之后,似乎没有代码,无论是内置的还是其他的,都可以满足我的需求。

我怎么能写一些东西来做到这一点?我原以为已经有人为此编写了一些代码;有什么我错过的吗?

【问题讨论】:

    标签: python image gtk pygtk


    【解决方案1】:

    您可以使用widget.get_allocation() 找出父widget 的大小并使用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 信号的函数中父小部件。为避免无限循环,请确保您放入小部件的图像不会再次改变其大小。

    参考资料:

    【讨论】:

    • 这很有帮助,谢谢。但是,我使用了image.set_from_pixbuf(pixbuf) 而不是image = gtk.image_new_from_pixbuf(pixbuf)
    【解决方案2】:

    这是一个在绘图区域上完成此任务的例外:

        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()
    

    【讨论】:

      【解决方案3】:

      这里有一些小的 sn-p 类,它允许您使用自动缩放的图像。

      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()
      

      【讨论】:

        猜你喜欢
        • 2012-07-26
        • 1970-01-01
        • 2011-09-03
        • 2019-04-08
        • 2021-09-08
        • 2013-11-05
        • 1970-01-01
        • 2017-01-27
        • 1970-01-01
        相关资源
        最近更新 更多