【问题标题】:How to draw a new line on Gtk::DrawingArea area, while peristing previous lines that have already been drawn?如何在 Gtk::DrawingArea 区域上绘制一条新线,同时保留之前已经绘制的线?
【发布时间】:2014-07-03 00:49:09
【问题描述】:

我在 Ubuntu 12.04 LTS 32 位上使用带有 gtkmm3 的 GNU 工具链的 C++11。 我一直在玩Programming with gtkmm 3 中 gtkmm3 的一些示例。

基于那里的17.2.1.Example,我从Gtk::DrawingArea(这里的MyDrawingArea)继承并覆盖on_draw()事件处理程序,如下所示:

MyDrawingArea.hpp

...

protected:

    bool on_draw ( const Cairo::RefPtr<Cairo::Context>& cr ) override;

MyDrawingArea.cpp

 bool MyDrawingArea::on_draw( const Cairo::RefPtr<Cairo::Context>& cr )
    {

        Gtk::Allocation allocation = get_allocation( );
        const int width = allocation.get_width( );
        const int height = allocation.get_height( );
        int coord1{ height - 3 };
        cr->set_line_width( 3.0 );

        this->get_window( )->freeze_updates( );

        cr->set_source_rgb( 0, 0.40, 0.60 );
        cr->move_to( 0, coord1 );
        cr->line_to( width, coord1 );
        cr->stroke( );

        cr->set_source_rgb( 1, 0.05, 1 );
        cr->move_to( mXStart, coord1 );
        cr->line_to( mXStart, mYAxis * 1.5 );
        cr->show_text( to_string( mYAxis ) );
        cr->stroke( );
        mXStart += 5;

        this->get_window( )->thaw_updates( );
        return true;

    }

我的目标是根据我在一个小测试应用程序中所做的计算绘制一个简单的条形图,其想法是每次调用 on_draw() 事件时,下一个条形图将向右移动 5 个单位mXAxis 并根据新的mYaxis 值绘制一条垂直线,该值是根据新计算的结果计算出来的。

当我想重绘我的图表并触发 MyDrawingArea::on_draw() 事件时,我会在计算完成后从我的应用程序中调用 MyDrawingArea.show_all(),并设置新的 x 轴和 y 轴。

但是,这并没有像我预期的那样工作:MyDrawingArea.show_all() 使整个绘图窗口无效并从头开始绘制:新的图形线出现在正确的位置,但之前的图形线被删除了。我也试过MyDrawingArea.queue_draw(),效果一样。 但我想保留以前的图表结果,以便在使用不同值进行计算时获得计算结果的概要。

此实现还导致我的图表上的底线(图表上的我的 x 轴) - 由我的代码示例中的第一个 stroke() 调用绘制,在每次调用 on_draw() 时重新呈现 - 尽管这不应该是必要的,因为这条线在MyDrawingArea 的整个生命周期内都会持续存在 - 不需要在每个新的on_draw() 事件上使其无效然后重新绘制它,就像我的代码目前正在做的那样,因为我还没有还没有找到处理这个问题的方法。

我对开罗很陌生,所以我确信我这样做可能完全错误,但是明确的、面向任务的文档似乎很少 - 没有找到任何解释如何做到这一点的东西,尽管我'我相信这很简单。

我需要做什么才能在Gtk::DrawingArea 上绘制一条新线,同时保留在之前的通道中已经绘制的先前图形线,并建立将在@987654337 的生命周期内持续存在的图形元素@小部件。显然使用show_all()queue_draw() 并在on_draw() 事件中完成这一切并不是要走的路。

【问题讨论】:

    标签: c++11 gtk gtk3 cairo gtkmm


    【解决方案1】:

    一般来说,您必须绘制整个小部件,Cairo 会将绘图剪辑到预定义的脏区。另请参阅 GTK 参考手册以获取“GtkWidget::draw”信号以获取性能提示:

    信号处理程序将获得一个 cr ,其中剪辑区域已设置为 小部件的脏区域,即需要重新绘制的区域。 想要避免完全重绘自己的复杂小部件 可以获得剪辑区域的完整范围 gdk_cairo_get_clip_rectangle(),或者他们可以获得更细粒度的 脏区的表示 cairo_copy_clip_rectangle_list().

    因此您可以使用 gtk_widget_queue_draw_area() 仅重绘您想要的区域。

    【讨论】:

    • 我看到了关于剪辑区域、脏区域等的文档和函数,但无法弄清楚脏区域是如何确定的以及如何计算它:因为之前的draw已经完了,下次不是都干净了吗? (我不仅是开罗的新手,我对这种编程也很陌生——我通常做中间件和服务器端的工作)无论如何,从你所说的看来,我有两个选择:坚持我以前的每次点并重画所有线;计算每次通过时我需要绘制的脏区并将绘制限制在该区域?
    • 脏区由窗口系统决定,使用 queue_draw*() 手动重绘的区域。所以是的,要么你重画所有,让剪裁为你做提升,或者你计算和排队你的脏区域,只在脏区域中绘制。最有可能的是,您可以重新绘制所有内容,无论如何它都会足够快,这要归功于剪辑。
    • 很可能,您可以重绘所有...:这就是我选择做的事情 - 对我来说更容易将以前绘制的线条存储在容器中并迭代重新绘制它们,而不是开始弄清楚如何获取脏区域并跟踪我应该在下一行的位置。这是一个非常简单的应用程序,只是为了自学基础知识,我预计不会遇到绘图会如此扩展和复杂以至于性能成为问题的情况,特别是因为正如您所解释的那样,剪裁将最大限度地减少命中。
    猜你喜欢
    • 2018-10-02
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 2011-07-14
    • 2018-12-19
    • 1970-01-01
    • 2014-04-05
    • 1970-01-01
    相关资源
    最近更新 更多