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

发布于 2024-10-17 02:01:39 字数 1306 浏览 4 评论 0原文

我在可调整大小的窗口中有一个 GtkImage 小部件,还有一个参考 GdkPixBuf 存储我想要填充 GtkImage 的图像。

我可以使用此方法缩放 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-event GTK 事件。每次更改窗口大小后,图像确实会正确缩放。然而,我对这个解决方案有两个问题:

  • 我只能使窗口更大。一旦图像被放大,GTK 不会让我将窗口调整得更小,因为窗口不能小于它的小部件。我理解为什么会这样,但我不知道如何改变这种行为。
  • 也许这没什么大不了的,但我更喜欢来自 GtkImage 小部件而不是顶级窗口的事件。

对于这么一个小问题的解释很长,我很抱歉,我希望你能够帮助我。

I have a GtkImage widget in a resizable window and a reference GdkPixBuf storing the image I want to fill the GtkImage with.

I can scale the GdkPixBuf to fill the GtkImage widget using this method:

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)

When I call update_image manually it works as expected. Now I want the scaling to occur automatically when the GtkImage widget is resized. The best solution I came with was to bind the update_image method to the configure-event GTK event of the window. After each size change of the window, the image is indeed properly scaled. However I have two issues with this solution:

  • I can only make the window bigger. Once the image has been upscaled, GTK won't let me resize the window smaller because the window can't be smaller than its widgets. I understand why it works like that but I don't know how to change this behaviour.
  • Maybe this is no big deal but I would have preferred an event from the GtkImage widget instead of the top-level window.

I am sorry for the long explanation of such a trivial problem, I hope you'll be able to help me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

圈圈圆圆圈圈 2024-10-24 02:01:39

我相信您可以使用 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()

希望这有帮助,问候

I believe you could use expose-event signal of the widget for image scaling. Also adding image into scrollable container should fix the problem with window resize. Please check if an example below would work for you.

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

hope this helps, regards

梦里°也失望 2024-10-24 02:01:39

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

我不了解Python,但这里有一个使用GTK3的C示例:

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 ()< /code> 完成后。

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

If you don't want to use a GtkScrolledWindow, you can replace your GtkImage with a GtkDrawingArea instead, and then draw your image using Cairo. This will allow the images to shrink, because GtkDrawingArea does not set a size request.

I don't know about Python, but here is an example in C using 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);

    .....
}

If the drawing area's background appears opaque, set gtk_widget_set_has_window () to FALSE, though it's probably better to derive your own widget from GtkDrawingArea and set this property in its init function.

If you're using GTK2, the code is similar, except that you have to call gdk_cairo_create () on widget->window and call cairo_destroy () when you're finished.

Also, with GTK2, if the GtkDrawingArea doesn't have its own GdkWindow, the coordinates for drawing are relative to the parent GdkWindow rather than the widget.

哭泣的笑容 2024-10-24 02:01:39

所有小部件都有 size-allocate< /a> (参见 PyGObject Gtk3) 信号。

当小部件被分配新的空间时,会发出“大小分配”信号。

也许你可以用它。

All widgets have size-allocate (cf. PyGObject Gtk3) signal.

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

Perhaps you can use that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文