我在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 (快速而又脏,仅用于概念演示)
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: 活动2:
我的问题是,显然,每次重新绘制窗口时都会触发MyDrawingArea.queue_draw()
事件处理程序。只需移动应用程序的主窗口(包含on_draw()
)会导致MyDrawingArea
触发,并且线条将呈现在新位置。
如何控制on_draw()
事件中的代码何时运行,以便只有在我的应用程序代码中调用on_draw()
时才重新呈现该行,但是在之前的状态保留为其他时间? (我不想想我询问如何防止MyDrawingArea.queue_draw()
被解雇,但也许这就是必须发生的事情?)
只需设置一个标志,通知我的事件已经进行了调用,然后只运行我的代码来渲染该行会引发其他问题,因为当没有设置标志时,我会丢失之前呈现的所有内容。
这似乎是一种不可能的情况:对于每个on_draw()
事件,行重新绘制在新位置,或者如果我使用标志调用绘图逻辑,则完全删除,on_draw()
触发何时没有设置该标志。
我该如何管理?我是否需要逻辑来管理两个不同的on_draw()
选项:如果应用程序进行调用,则渲染新版本的行,如果没有,则重新绘制旧版本?这变得复杂 - 我以为我错过了什么。我应该使用不同的事件吗?我可以从on_draw()
有关谁可以帮助我协商此问题的Cairo::Context
等信息中获取某种方式吗?
答案 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,
,它只是重绘以前的内容,而新的绘图仅在从应用程序显式发出信号时发生。