2017-06-07 28 views
0

私はカスタムのスクロール可能なテキスト領域を作成しようとしています。私はGridの中にDrawingAreaScrollBarを作成しました。私は、DrawingAreaのイベントをScrollBarの値を単に見て、Pango.Layoutを描画する前にCairo.Contextを適切に動かす方法をthis.on_drawの方法に付けました。Gtk - 間違ったウィジェットに対して描画イベントが発生し、再描画されないウィジェット

最初の問題はScrollBarでイベントを登録していなくてもScrollBarに触れるたびにthis.on_drawが呼び出されることです。どうすればこれを防ぐことができますか?

第二の問題は、this.on_drawが起動されていてもScrollBar値が0または100(100調整の上限値)付近にある場合を除き、Contextに加えた変更が表示されないことです。なぜこうなった?

私はDrawingAreaqueue_redrawを呼び出す方法にScrollBarvalue_changedイベントをconnectた場合、それはthis.on_drawを起動し、それの後にそれを正しく表示するであろうことを知りました。しかし、第2の問題のために、私はthis.on_drawが不必要に何回も呼び出されていると思います。それで、これを達成する「正しい」方法は何ですか?

using Cairo; 
using Gdk; 
using Gtk; 
using Pango; 

public class Texter : Gtk.Window { 
    private Gtk.DrawingArea darea; 
    private Gtk.Scrollbar scroll; 

    private string text = "Hello\nWorld!"; 

    public Texter() { 
     GLib.Object (type: Gtk.WindowType.TOPLEVEL); 

     Gtk.Grid grid = new Gtk.Grid(); 
     this.add (grid); 

     var drawing_area = new Gtk.DrawingArea(); 
     drawing_area.set_size_request (200, 200); 
     drawing_area.expand = true; 
     drawing_area.draw.connect (this.on_draw); 

     grid.attach (drawing_area, 0, 0); 

     var scrollbar = new Gtk.Scrollbar (Gtk.Orientation.VERTICAL, 
              new Gtk.Adjustment(0, 0, 100, 0, 0, 1)); 

     grid.attach (scrollbar, 1, 0); 

     this.darea = drawing_area; 
     this.scroll = scrollbar; 

     this.destroy.connect (Gtk.main_quit); 
    } 

    private bool on_draw (Gtk.Widget sender, Cairo.Context ctx) { 
     ctx.set_source_rgb (0.9, 0.9, 0.9); 
     ctx.paint(); 

     var y_offset = this.scroll.get_value(); 
     stdout.printf("%f\n", y_offset); 

     ctx.set_source_rgb (0.25, 0.25, 0.25); 
     ctx.move_to(0, 100 - y_offset); 

     var layout = Pango.cairo_create_layout(ctx); 
     layout.set_font_description(Pango.FontDescription.from_string("Sans 12")); 
     layout.set_auto_dir(false); 
     layout.set_text(this.text, this.text.length); 
     Pango.cairo_show_layout(ctx, layout); 

     return false; 
    } 

    static int main (string[] args) { 
     Gtk.init (ref args); 

     var window = new Texter(); 
     window.show_all(); 

     Gtk.main(); 

     return 0; 
    } 
} 

また、上記のコードで見つかった場合は、(関連性のない)間違いを指摘してください。

+0

これはどのバージョンのGTK +ですか?最初の問題はオーバーレイスクロールバーに起因すると思われますが、これはオーバーレイスクロールバーを持つGTK +を使用しているかどうかによって異なります。 – andlabs

+0

@andlabs '--pkg gtk + -3.0'オプションでコンパイルし、インストールされたgtk3のバージョンは' 3.22'です。 「オーバーレイスクロールバー」とは、その上にマウスを置いたときに拡大するものを意味する場合、少なくとも視覚的にはそうではありませんでした。それは通常の古い3.0スクロールバーのように "見た目"です。 http://imgur.com/a/NpCui(ただし、それをホバリングしても、再描画イベントが発生したため、1つの動作をしました)どうすればその動作を無効にできますか? – John

答えて

2

あなたが紛失している部分は、ではなく、という意味の "再描画すべて"という意味です。その代わりに、GTK +はカイロコンテキストのクリップ領域を再描画する必要のある部分に設定します。それ以外の処理は効果がありません。カイロ関数cairo_clip_extents()は、その地域が何であるかを伝えます。 GtkWidgetのqueue_draw_area()メソッドは、ウィジェット全体ではなく、描画のために特定の領域を明示的にマークすることを可能にします。

しかし、スクロールバーへのあなたのやり方は間違っています。最初からインフラストラクチャ全体を構築しようとしています!代わりにGtkScrolledWindowの使用を検討してください。これは自動的にあなたのためのスクロールのすべての詳細を処理し、私に言及したオーバーレイスクロールバーを提供します。あなたがする必要があるのは、GtkDrawingAreaのサイズをあなたが望むサイズに設定することだけです.GtkScrolledWindowは残りの処理を行います。これを行うには、GtkDrawingAreaをサブクラス化し、get_preferred_height()get_preferred_width()の仮想関数をオーバーライドする必要があります(最小サイズと自然サイズの両方を、その特定の次元に必要なサイズに設定してください)。このサイズを後で変更する必要がある場合は、GtkWidgetのqueue_resize()メソッドを呼び出します。あなたはおそらくset_size_request()を使用して取得することができますが、私はこれを行うのが好ましい方法です。)これはまた、あなたのカイロの座標を変換することを心配する必要はありません利点を提供します。 GtkScrolledWindowがこれを行います。

関連する問題