GTK-为错误的小部件发射的抽奖活动,而窗口小部件不重新绘制



我正在尝试创建一个自定义的可滚动文本区域。我在Grid内创建了DrawingAreaScrollBar。我已将DrawingAreadraw事件附加到this.on_draw方法,该方法只需查看ScrollBar的值并在绘制Pango.Layout之前适当地移动Cairo.Context

第一个问题是,即使我尚未使用ScrollBar注册任何事件,this.on_draw即使触摸ScrollBar。我该如何防止它或检查?

第二个问题是,即使调用了this.on_draw,除非ScrollBar值接近0100(100是调整的上值(,否则对Context进行的更改也不会显示。为什么会发生?

我确实发现,如果我将 value_changed的 CC_19事件 ScrollBar发生到一种调用 DrawingAreaqueue_redraw的方法,它将调用 this.on_draw并在其之后正确显示。但是由于第二个问题,我认为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 = "HellonWorld!";
    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("%fn", 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;
    }
}

另外,如果您在上述代码中找到一个(可能是无关的(错误。

您缺少的部分是draw信号不是表示"重新绘制所有内容"。取而代之的是,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为您执行此操作。

最新更新