2011-02-08 18 views
5

Tengo un widget GtkImage en una ventana de tamaño variable y una referencia GdkPixBuf que almacena la imagen con la que quiero llenar el GtkImage.Escalado de imagen automático al cambiar el tamaño con (Py) GTK

puedo escalar la GdkPixBuf para llenar el widget GtkImage usando este método:

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) 

Cuando llamo update_image manualmente funciona como se esperaba. Ahora quiero que la escala se produzca automáticamente cuando se cambie el tamaño del widget GtkImage. La mejor solución que obtuve fue enlazar el método update_image con el evento GTK configure-event de la ventana. Después de cada cambio de tamaño de la ventana, la imagen está correctamente escalada. Sin embargo, tengo dos problemas con esta solución:

  • Solo puedo agrandar la ventana. Una vez que la imagen ha sido escalada, GTK no me permitirá cambiar el tamaño de la ventana más pequeña porque la ventana no puede ser más pequeña que sus widgets. Entiendo por qué funciona así, pero no sé cómo cambiar este comportamiento.
  • Quizás esto no es gran cosa, pero hubiera preferido un evento del widget GtkImage en lugar de la ventana de nivel superior.

Disculpa la larga explicación de un problema tan trivial, espero que puedas ayudarme.

Respuesta

9

Creo que podría usar la señal expose-event del widget para escalar la imagen. Además, agregar imagen al contenedor desplazable debería solucionar el problema con el cambio de tamaño de la ventana. Por favor, compruebe si un ejemplo a continuación podría funcionar para usted.

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

esperanza que esta ayuda, que se refiere a

+1

Muchas gracias, el truco de ScrolledWindow funcionó. Obtengo un 'GtkWarning: gtk_scrolled_window_add(): no se puede agregar el widget no desplazable use gtk_scrolled_window_add_with_viewport() en su lugar', pero si agrego una ventana gráfica, aparecen las barras de desplazamiento cuando reduzco el tamaño de la ventana, así que lo dejo así por ahora. Se llama al 'expose-event' en cada iteración de gtk, por lo que maximiza el uso de la CPU. – Jim

0

Todos los widgets tienen size-allocate señal.

La señal de "asignación de tamaño" se emite cuando el widget recibe una nueva asignación de espacio.

Quizás pueda usar eso.

0

Si no desea utilizar un GtkScrolledWindow, puede reemplazar su GtkImage con un GtkDrawingArea y luego dibujar su imagen con Cairo. Esto permitirá que las imágenes se contraigan, porque GtkDrawingArea no establece una solicitud de tamaño.

No sé sobre Python, pero aquí es un ejemplo en C usando 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); 

    ..... 
} 

Si el fondo del área de dibujo del aparece opaca, establece gtk_widget_set_has_window() a FALSE, aunque es probable que sea mejor para derivar su propio widget desde GtkDrawingArea y establecer esta propiedad en su función init.

Si está utilizando GTK2, el código es similar, excepto que debe llamar al gdk_cairo_create() en widget->window y llamar al cairo_destroy() cuando termine.

Además, con GTK2, si el GtkDrawingArea no tiene su propio GdkWindow, las coordenadas de dibujo son en relación con el padre en lugar de GdkWindow el widget.

Cuestiones relacionadas