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

C++ 如何控制代码何时在gktmm3 Gtk::DrawingArea的on_draw事件中执行,c++,gtk,cairo,gtkmm,C++,Gtk,Cairo,Gtkmm,我正在Ubuntu 12.04 LTS 32位上使用带有gtkmm3的GNU工具链的C++11。 我一直在试验gtkmm3中的一些示例 在此基础上,我继承了Gtk::DrawingArea MyDrawingArea,并对on_draw事件处理程序进行了如下重写: MyDrawingArea.hpp MyDrawingArea.cpp快速且肮脏,仅用于概念演示 此代码绘制一条对角线。当我通过应用程序中的事件处理程序调用MyDrawingArea.queue\u draw时,我希望它的位置发生变化

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

在此基础上,我继承了Gtk::DrawingArea MyDrawingArea,并对on_draw事件处理程序进行了如下重写:

MyDrawingArea.hpp

MyDrawingArea.cpp快速且肮脏,仅用于概念演示

此代码绘制一条对角线。当我通过应用程序中的事件处理程序调用MyDrawingArea.queue\u draw时,我希望它的位置发生变化。这项工作:

事件1: 事件2:

我的问题是,很明显,每次重新绘制窗口时,on_draw事件处理程序都会触发。只需移动包含MyDrawingArea的应用程序主窗口,就会触发on_draw并在新位置渲染线条

我如何控制我的on_draw事件中的代码何时运行,以便仅当我在应用程序代码中调用MyDrawingArea.queue_draw时,该行才会重新呈现,但在其他时间会保持其以前的状态?我不认为我是在问如何防止on_draw开火,但也许这就是必须发生的事情

简单地设置一个标志,通知我的事件已经进行了调用,然后才运行我的代码来呈现行,这会引发其他问题,因为如果没有设置标志,我将丢失以前呈现的所有内容

这似乎是一种不可能的情况:要么为每个on_draw事件在新位置重新绘制线,要么在使用标志调用绘图逻辑时完全擦除线,并且在未设置该标志时on_draw触发


我应该如何处理这个问题?我是否需要逻辑来管理两个不同的on_draw选项:如果应用程序调用,则渲染新版本的线条,如果不需要,则重新绘制旧版本?事情变得复杂了,我想我错过了什么。我是否应该使用其他事件?我可以从Cairo::上下文信息中获得关于谁调用了_draw等的信息来帮助我解决这个问题吗?

如果您打算使用切换按钮打开/关闭Gtk.drawing区域,只需询问切换按钮是否处于活动状态,然后重新绘制该区域

<!------ 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的最后一个渲染副本放在缓冲区中的某个位置,当您准备再次触发它时,再次连接,但这次不要从draw signal param获取cairo*cr。如果您打算使用切换按钮打开/关闭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的最后一个渲染副本放在缓冲区中的某个位置,当您准备再次触发它时,再次连接,但这次不要从draw signal param获取cairo*cr。使用副本

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

开启时表示不同信号状态的枚举:

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

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

DS_ClearSignal 
表示完全清除绘图区域并重新开始

MyDrawingArea类有一个成员:

Draw_Signals mDSignal{Draw_Signals::DS_HoldSignal}

该值由triggeron_使用setter方法从我的应用程序中提取的方法设置

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


这里的关键是默认状态始终为Draw_Signals::DS_HoldSignal,它只是重新绘制以前的内容,只有当应用程序明确发出其他信号时,才会出现新的绘制。

我通过编写一个小状态机来解决这个问题,该状态机控制on_Draw事件的行为:

开启时表示不同信号状态的枚举:

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

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

DS_ClearSignal 
表示完全清除绘图区域并重新开始

MyDrawingArea类有一个成员:

Draw_Signals mDSignal{Draw_Signals::DS_HoldSignal}

该值由triggeron_使用setter方法从我的应用程序中提取的方法设置

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

这里的关键是默认状态始终为Draw_Signals::DS_HoldSignal,它只是重新绘制以前的内容,只有当应用程序明确发出相反的信号时,新绘图才会出现。

将cr的最后一个渲染副本放在缓冲区的某个位置-我正在处理这个问题,并意识到这可能是我必须做的-请参阅我刚刚发布的编辑:我需要逻辑吗。。。它完全包括您建议的选项。我可以通过将旧的行参数保存在某个容器中来实现。实际的
应用程序比我在这里提到的更复杂,需要更多的参数,但它是可行的。但是应该有一个更简单的方法。。。如果没有人能想出更好的办法,你会得到分数的。很高兴能帮上忙,祝你的项目好运。如果有一种更简单的方法,并且您找到了它,让我知道只需询问切换按钮是否处于活动状态-按钮不在处理渲染的类的范围内。它必须是在呈现类中设置的状态信息,或者是在对该类的函数调用中设置的参数-可以在控制器类中的中心函数中设置,该控制器类对所有潜在相关的前端成员可见并可调用。将渲染逻辑绑定到前端的特定组件不是一个好主意:紧密耦合。将cr的最后一个渲染副本放在缓冲区中的某个位置-我正在处理这个问题,并意识到这可能是我必须做的-请参阅我刚刚发布的编辑:我需要逻辑吗。。。它完全包括您建议的选项。我可以通过将旧的行参数保存在某个容器中来实现。实际的应用程序比我在这里提到的更复杂,需要更多的参数,但它是可行的。但是应该有一个更简单的方法。。。如果没有人能想出更好的办法,你会得到分数的。很高兴能帮上忙,祝你的项目好运。如果有一种更简单的方法,并且您找到了它,让我知道只需询问切换按钮是否处于活动状态-按钮不在处理渲染的类的范围内。它必须是在呈现类中设置的状态信息,或者是在对该类的函数调用中设置的参数-可以在控制器类中的中心函数中设置,该控制器类对所有潜在相关的前端成员可见并可调用。将渲染逻辑绑定到前端的特定组件(紧耦合)不是一个好主意。
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;

    }