Автоматическое масштабирование изображения при изменении размера с помощью (Py) GTK - PullRequest
6 голосов
/ 09 февраля 2011

У меня есть виджет 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 вместо окна верхнего уровня.

Извините за длинное объяснение такой тривиальной проблемы, надеюсь, вы сможете мне помочь.

Ответы [ 3 ]

10 голосов
/ 09 февраля 2011

Полагаю, вы можете использовать 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()

надеюсь, это поможет, с уважением

1 голос
/ 31 августа 2014

Все виджеты имеют сигнал size-allocate.

Сигнал "size-allocate" испускается, когда виджету назначается новое пространство.

Возможно, вы можете использовать это.

0 голосов
/ 26 января 2016

Если вы не хотите использовать GtkScrolledWindow, вы можете заменить вместо него GtkImage на GtkDrawingArea, а затем нарисовать изображение с помощью 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, код аналогичен, за исключением того, что вам нужно позвонить gdk_cairo_create () на widget->window и позвонить cairo_destroy (), когда вы закончите.

Кроме того, в GTK2, если GtkDrawingArea не имеет собственного GdkWindow, координаты для рисования относительно родительского элемента GdkWindow, а не виджета.

...