Автоматическое масштабирование изображения при изменении размера с помощью (Py)GTK
у меня есть 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 ответов
Я верю, что вы могли бы использовать 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()
надеюсь, это поможет, с уважением
все виджеты имеют size-allocate
сигнал.
сигнал "size-allocate" испускается, когда виджету дается новое распределение пространства.
возможно, вы можете использовать это.
если вы не хотите использовать 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 ()
to FALSE
, хотя, вероятно, лучше получить свой собственный виджет из GtkDrawingArea
и установить это собственность в своем .
если вы используете GTK2, код похож, за исключением того, что вы должны позвонить gdk_cairo_create ()
on widget->window
и звонок cairo_destroy ()
когда вы закончите.
кроме того, с GTK2, если GtkDrawingArea
не имеет собственного GdkWindow
, координаты для рисования относительно родительского GdkWindow
вместо виджета.