You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

gtkmm中signal_draw信号处理函数为何必须返回int?返回0是否合规?

问题

正在开发一个展示谢尔宾斯基三角形的程序,首次使用Cairo库,先编写了绘制单条线的演示代码。发现绑定到signal_draw信号的on_D_Triangle_draw函数必须返回int类型,若设为void会触发编译错误(错误信息附后),现咨询该现象的原因,以及返回0是否符合最佳实践。

代码示例

#include <glibmm.h>
#include <gtkmm.h>

Gtk::Window* W_Main;
Gtk::DrawingArea* D_Triangle;
Gtk::Button* B_Draw;
Gtk::Adjustment* A_Depth;

int on_D_Triangle_draw(const Cairo::RefPtr<Cairo::Context> cr) {
    cr->set_source_rgb(0.0, 0.0, 0.0);
    cr->set_line_width(4.0);
    cr->move_to(0, 0);
    cr->line_to(30, 30);
    cr->stroke();
    return 0;
}

int main(int argc, char** argv) {
    auto app = Gtk::Application::create(argc, argv, "org.CENSORED.sierpinski");
    
    auto builder = Gtk::Builder::create_from_file("sierpinski.glade");
    
    builder->get_widget("W_Main", W_Main);
    builder->get_widget("D_Triangle", D_Triangle);
    builder->get_widget("B_Draw", B_Draw);
    builder->get_widget("A_Depth", A_Depth);
    
    D_Triangle->signal_draw().connect(sigc::ptr_fun(on_D_Triangle_draw));
    
    app->run(*W_Main);
}

编译错误信息

In file included from /usr/include/sigc++-2.0/sigc++/signal_base.h:27,
                 from /usr/include/sigc++-2.0/sigc++/signal.h:8,
                 from /usr/include/sigc++-2.0/sigc++/sigc++.h:123,
                 from /usr/include/glibmm-2.4/glibmm/thread.h:50,
                 from /usr/include/glibmm-2.4/glibmm.h:103,
                 from sierpinski.cpp:1:
/usr/include/sigc++-2.0/sigc++/functors/slot.h: In instantiation of ‘static T_return sigc::internal::slot_call1<T_functor, T_return, T_arg1>::call_it(sigc::internal::slot_rep*, sigc::type_trait_take_t<T_arg3>) [with T_functor = sigc::pointer_functor1<Cairo::RefPtr<Cairo::Context>, void>; T_return = bool; T_arg1 = const Cairo::RefPtr<Cairo::Context>&; sigc::type_trait_take_t<T_arg3> = const Cairo::RefPtr<Cairo::Context>&]’:
/usr/include/sigc++-2.0/sigc++/functors/slot.h:177:56:   required from ‘static void* (* sigc::internal::slot_call1<T_functor, T_return, T_arg1>::address())(void*) [with T_functor = sigc::pointer_functor1<Cairo::RefPtr<Cairo::Context>, void>; T_return = bool; T_arg1 = const Cairo::RefPtr<Cairo::Context>&; sigc::internal::hook = void* (*)(void*)]’:
/usr/include/sigc++-2.0/sigc++/functors/slot.h:679:90:   required from ‘sigc::slot1<T_return, T_arg1>::slot1(const T_functor&) [with T_functor = sigc::pointer_functor1<Cairo::RefPtr<Cairo::Context>, void>; T_return = bool; T_arg1 = const Cairo::RefPtr<Cairo::Context>&]’:
/usr/include/sigc++-2.0/sigc++/functors/slot.h:1843:26:   required from ‘sigc::slot<T_return, T_arg1, sigc::nil, sigc::nil, sigc::nil, sigc::nil, sigc::nil, sigc::nil>::slot(const T_functor&) [with T_functor = sigc::pointer_functor1<Cairo::RefPtr<Cairo::Context>, void>; T_return = bool; T_arg1 = const Cairo::RefPtr<Cairo::Context>&]’:
sierpinski.cpp:40:38:   required from here
/usr/include/sigc++-2.0/sigc++/functors/slot.h:170:16: error: void value not ignored as it ought to be
  169 |       return (typed_rep->functor_).SIGC_WORKAROUND_OPERATOR_PARENTHESES<type_trait_take_t<T_arg1>>
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  170 |                (a_1);
      |                ^~~~~
回答

错误原因

Gtk::DrawingArea的signal_draw信号要求回调函数返回bool类型(你用int能编译是因为C++中int和bool可以隐式转换,但这不是规范写法)。从编译错误信息里能看到T_return = bool,说明信号机制期望得到一个布尔值。

当你把回调设为void返回时,sigc绑定框架会尝试将void返回值当作bool来接收,这就触发了编译错误——C不允许忽略void值去赋值给需要bool的变量,也就是错误提示里的“void value not ignored as it ought to be”。

这个返回值的作用是告诉GTK是否已经处理完绘制事件:

  • 返回true(或非0的int):表示你已经完成了所有绘制工作,GTK不需要再执行默认的绘制逻辑(比如清除背景)
  • 返回false(或0):表示你只做了部分绘制,需要GTK完成剩余的默认绘制动作

最佳实践

你返回0(等价于false)是合理的场景之一:如果你的回调只绘制了线条,需要GTK帮忙处理背景清除等默认操作,返回0没问题。

但有两个优化建议:

  1. 把回调函数的返回类型改成bool,这完全符合GTKmm的接口定义,代码可读性更强,也能避免隐式转换带来的潜在问题
  2. 如果你后续的谢尔宾斯基三角形绘制会覆盖整个DrawingArea区域,应该返回true(或1),这样GTK不会重复执行默认绘制,能节省资源

内容的提问来源于stack exchange,提问作者AlgebraicsAnonymous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:00:37