如何控制代码在gktmm3-Gtk :: DrawingArea的on_draw事件中执行的时间

时间:2014-07-14 01:00:49

标签: c++ gtk cairo gtkmm

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

基于17.2.1.Example,我继承自Gtk::DrawingAreaMyDrawingArea此处)并覆盖on_draw()事件处理程序,如下所示:

MyDrawingArea.hpp

...

protected:

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

MyDrawingArea.cpp (快速而又脏,仅用于概念演示)

double y{ 10 };
double x{ 10 };

bool MyDrawingArea::on_draw( const Cairo::RefPtr<Cairo::Context>& cr )
{
        this->get_window( )->freeze_updates( );
        cr->set_line_width( 3.0 );
        cr->set_source_rgb( 1, 0, 0 );
        cr->move_to( x, y );
        cr->line_to( x * 2, y * 2 );
        cr->stroke( );
        this->get_window( )->thaw_updates( );
        x += 50;
        y += 50;
        return true;
 }

此代码绘制单个对角线。当我通过应用程序中的事件处理程序调用{​​{1}}时,我希望它的位置发生变化。这有效:

活动1: enter image description here 活动2: enter image description here

我的问题是,显然,每次重新绘制窗口时都会触发MyDrawingArea.queue_draw()事件处理程序。只需移动应用程序的主窗口(包含on_draw())会导致MyDrawingArea触发,并且线条将呈现在新位置。

如何控制on_draw()事件中的代码何时运行,以便只有在我的应用程序代码中调用on_draw()时才重新呈现该行,但是在之前的状态保留为其他时间? (我不想我询问如何防止MyDrawingArea.queue_draw()被解雇,但也许这就是必须发生的事情?)

只需设置一个标志,通知我的事件已经进行了调用,然后只运行我的代码来渲染该行会引发其他问题,因为当没有设置标志时,我会丢失之前呈现的所有内容。

这似乎是一种不可能的情况:对于每个on_draw()事件,行重新绘制在新位置,或者如果我使用标志调用绘图逻辑,则完全删除,on_draw()触发何时没有设置该标志。

我该如何管理?我是否需要逻辑来管理两个不同的on_draw()选项:如果应用程序进行调用,则渲染新版本的行,如果没有,则重新绘制旧版本?这变得复杂 - 我以为我错过了什么。我应该使用不同的事件吗?我可以从on_draw()有关谁可以帮助我协商此问题的Cairo::Context等信息中获取某种方式吗?

2 个答案:

答案 0 :(得分:2)

如果您打算使用切换按钮打开/关闭Gtk.DrawingArea,只需询问切换按钮是否有效而不是重绘该区域。

<!------ language python ------>
def on_draw (self, widget):
    # your cairo draw here
    ......
    ......
    if toggle_button.get_active () is True: #toggle to show DrawingArea
        x+=50
        y+=50
    # other than that it simply sits there doing nothing 

现在,关于断开“绘制”信号。将cr的最后渲染副本放在缓冲区的某处,当你准备再次触发它时,再次连接,但这次没有得到“绘制”信号的cairo * cr PARAM。使用副本

答案 1 :(得分:1)

我通过编写一个控制on_draw()事件行为方式的小型状态机来解决这个问题:

on_draw()点火时代表不同信号状态的枚举:

enum class Draw_Signals
{
    DS_RedrawSignal, DS_HoldSignal, DS_ClearSignal, DS_End
};

DS_RedrawSignal 

表示根据最近的应用程序活动重新绘制新添加/更改。

DS_HoldSignal 

表示保持当前图形状态但不执行任何新操作。

DS_ClearSignal 

完全清除绘图区域并重新开始。

MyDrawingArea类有一个成员:

Draw_Signals mDSignal { Draw_Signals::DS_HoldSignal };

此值由使用“setter”方法从我的应用程序触发on_draw()的方法设置。

我没有详细介绍所有细节,MyDrawingArea::on_draw()现在看起来像这样:

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

        get_window( )->freeze_updates( );

        switch ( mDSignal )
          {
            case Draw_Signals::DS_RedrawSignal:
              {
                DrawNewLine( cr );//draws new line and caches it for use when RedrawOldLine() is called.
                break;
              }

            case Draw_Signals::DS_HoldSignal:
              {
                RedrawOldLine( cr );
                break;
              }

            case Draw_Signals::DS_ClearSignal:
              {
                clearDrawArea( );
              }

          }

        get_window( )->thaw_updates( );

        mDSignal = Draw_Signals::DS_HoldSignal;

        return true;

    }

他们在这里键入是默认状态始终为Draw_Signals::DS_HoldSignal,,它只是重绘以前的内容,而新的绘图仅在从应用程序显式发出信号时发生。