使用(Py)GTK调整大小时自动缩放图像

2024-04-28 22:46:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我在一个可调整大小的窗口中有一个GtkImage小部件,还有一个用于存储我要填充的GtkImage图像的引用GdkPixBuf

我可以使用以下方法缩放GdkPixBuf以填充GtkImage小部件:

def update_image(self, widget=None, data=None):
    # Get the size of the source pixmap
    src_width, src_height = self.current_image.get_width(), self.current_image.get_height()

    # Get the size of the widget area
    widget = self.builder.get_object('image')
    allocation = widget.get_allocation()
    dst_width, dst_height = allocation.width, allocation.height

    # Scale preserving ratio
    scale = min(float(dst_width)/src_width, float(dst_height)/src_height)
    new_width = int(scale*src_width)
    new_height = int(scale*src_height)
    pixbuf = self.current_image.scale_simple(new_width, new_height, gtk.gdk.INTERP_BILINEAR)

    # Put the generated pixbuf in the GtkImage widget
    widget.set_from_pixbuf(pixbuf)

当我手动调用update_image时,它按预期工作。现在我希望在调整GtkImage小部件的大小时自动进行缩放。我得到的最佳解决方案是将update_image方法绑定到窗口的configure-eventGTK事件。每次窗口大小改变后,图像确实正确缩放。但是,我对这个解决方案有两个问题:

  • 我只能把窗户变大。一旦图像被放大,GTK不允许我调整窗口的大小,因为窗口不能小于它的小部件。我明白为什么会这样,但我不知道如何改变这种行为。
  • 也许这没什么大不了的,但我更喜欢GtkImage小部件中的事件,而不是顶层窗口。

我很抱歉对这样一个小问题作了长时间的解释,希望你能帮助我。


Tags: theimageselfsrcnewget部件widget
0条回答
网友
1楼 · 发布于 2024-04-28 22:46:41

所有小部件都有^{}信号。

The "size-allocate" signal is emitted when widget is given a new space allocation.

也许你可以用这个。

网友
2楼 · 发布于 2024-04-28 22:46:41

如果不想使用GtkScrolledWindow,可以用GtkDrawingArea替换GtkImage,然后使用Cairo绘制图像。这将允许图像收缩,因为GtkDrawingArea未设置大小请求。

我不知道Python,但下面是C中使用GTK3的一个例子:

gboolean drawing_area_draw (GtkWidget *widget, cairo_t *cr, GdkPixbuf *current_image)
{

    .....   //Calculate size

    pixbuf = gdk_pixbuf_scale_simple (current_image,
                                    new_width,
                                    new_height,
                                    GDK_INTERP_BILINEAR);

    gdk_cairo_set_source_pixbuf (cr, 
                                pixbuf,
                                allocation.width/2 - new_width/2, 
                                allocation.height/2 - new_height/2);
    cairo_paint (cr);

    return FALSE;
}

int main (int argc, char *argv[])
{
    .....

    drawing_area = gtk_drawing_area_new ();
    g_signal_connect (G_OBJECT (drawing_area), "draw",
            G_CALLBACK (drawing_area_draw), current_image);

    .....
}

如果绘图区域的背景看起来不透明,请将gtk_widget_set_has_window ()设置为FALSE,不过最好从GtkDrawingArea派生自己的小部件,并在其init函数中设置此属性。

如果您使用的是GTK2,则代码是类似的,只是您必须在widget->window上调用gdk_cairo_create (),并在完成后调用cairo_destroy ()

另外,对于GTK2,如果GtkDrawingArea没有自己的GdkWindow,则用于绘制的坐标是相对于父对象的GdkWindow,而不是小部件的。

网友
3楼 · 发布于 2024-04-28 22:46:41

我相信您可以使用小部件的expose-event信号进行图像缩放。另外,将图像添加到可滚动的容器中可以解决窗口大小调整的问题。请检查下面的例子是否适合您。

import gtk

class ScaleImage:
    def __init__(self):
        self.temp_height = 0
        self.temp_width = 0

        window = gtk.Window(gtk.WINDOW_TOPLEVEL)

        image = gtk.Image()
        image.set_from_file('/home/my_test_image.jpg')
        self.pixbuf = image.get_pixbuf()
        image.connect('expose-event', self.on_image_resize, window)    

        box = gtk.ScrolledWindow()
        box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        box.add(image)

        window.add(box)
        window.set_size_request(300, 300)
        window.show_all()        

    def on_image_resize(self, widget, event, window):
        allocation = widget.get_allocation()
        if self.temp_height != allocation.height or self.temp_width != allocation.width:
            self.temp_height = allocation.height
            self.temp_width = allocation.width
            pixbuf = self.pixbuf.scale_simple(allocation.width, allocation.height, gtk.gdk.INTERP_BILINEAR)
            widget.set_from_pixbuf(pixbuf)

    def close_application(self, widget, event, data=None):
        gtk.main_quit()
        return False

if __name__ == "__main__":
    ScaleImage()
    gtk.main()

希望这有帮助,问候

相关问题 更多 >