2011-02-08 11 views
5

サイズ変更可能なウィンドウにGtkImageウィジェットがあり、画像が保存されているGdkPixBufGtkImageと記入したいと思います。(Py)GTKでサイズ変更時の自動画像スケーリング

私は、このメソッドを使用してGtkImageウィジェットを埋めるためにGdkPixBufを拡張することができます

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ウィジェットのサイズを変更すると自動的にスケーリングが行われるようにします。私が来た最善の解決策は、ウィンドウのconfigure-event GTKイベントにupdate_imageメソッドをバインドすることでした。ウィンドウの各サイズ変更の後、画像は実際に適切にスケーリングされます。しかし、私はこの解決策に2つの問題があります:

  • 私はウィンドウを大きくすることができます。イメージがアップスケールされると、GTKはウィンドウがそのウィジェットよりも小さくなることができないので、ウィンドウのサイズを小さくすることはできません。私はそれがなぜそれのように動作するのか理解していますが、私はこの振る舞いをどのように変更するのかわかりませ
  • これは大したことではないかもしれませんが、トップレベルウィンドウの代わりにGtkImageウィジェットからイベントを優先させてもらいました。

このような些細な問題について長い説明をおかけして申し訳ありませんが、私はあなたを助けてくれることを願っています。

答えて

9

画像スケーリングのためにウィジェットの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

ありがとう、ScrolledWindowトリックがうまくいきました。 gtk_scrolled_window_add():代わりにgtk_scrolled_window_add_with_viewport()を使うことはできませんが、ビューポートを追加するとウィンドウのサイズを小さくするとスクロールバーが現れますので、今のように残しておきます。 'expose-event'は各gtk反復で呼び出されるので、CPU使用量を最大にしました。 – Jim

0

すべてのウィジェットがsize-allocate信号を持って考えています。

「size-allocate」シグナルは、ウィジェットに新しいスペース割り当てが与えられたときに生成されます。

おそらくそれを使用できます。

0

あなたがGtkScrolledWindowを使用したくない場合は、代わりにGtkDrawingAreaであなたのGtkImageを交換して、カイロを使用して画像を描画することができます。 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); 

    ..... 
} 

描画領域の背景が不透明に表示された場合は、FALSEgtk_widget_set_has_window()を設定しましたウィジェットをGtkDrawingAreaに設定し、このプロパティをinit関数に設定します。

GTK2を使用している場合は、gdk_cairo_create()widget->windowに電話し、終了したらcairo_destroy()に電話する必要がある点を除いて、コードは似ています。

また、GtkDrawingAreaに独自のGdkWindowがない場合、描画の座標は、ウィジェットではなく親GdkWindowに相対的です。

関連する問題