能否以组合而非继承方式使用GTKmm的Gtk::DrawingArea?
能否用组合方式替代继承Gtk::DrawingArea?
在GTKmm官方入门示例及更复杂的时钟示例中,均通过继承public Gtk::DrawingArea来构建应用。是否可以采用组合方式使用DrawingArea,而非继承并覆写on_draw虚方法?我希望如此操作,以避免自定义方法/属性与Gtk::DrawingArea基类的继承方法混淆,从而明确区分访问的是自定义内容还是DrawingArea的内容。
当然可以!完全没必要非得继承Gtk::DrawingArea才能实现自定义绘制——Gtkmm的信号机制天生就支持这种组合式的设计思路,正好能满足你避免命名混淆的需求。
核心思路很简单:创建一个普通的自定义类,把Gtk::DrawingArea作为类的成员变量,然后通过连接它的draw信号来替代继承时覆写的on_draw虚方法。这样所有属于DrawingArea的方法和属性都需要通过成员变量来访问,和你的自定义方法/属性边界清晰,完全不会混淆。
给你一个简单的示例代码:
#include <gtkmm.h> class MyCustomWidget { public: MyCustomWidget() { // 把DrawingArea的draw信号连接到我们自定义的处理函数 m_drawing_area.signal_draw().connect( sigc::mem_fun(*this, &MyCustomWidget::handle_draw) ); // 如果需要处理其他事件,比如鼠标点击,同样用信号连接 m_drawing_area.signal_button_press_event().connect( sigc::mem_fun(*this, &MyCustomWidget::handle_mouse_click) ); } // 提供一个接口,让外部能获取内部的DrawingArea,方便添加到窗口或容器中 Gtk::Widget& get_widget() { return m_drawing_area; } private: // 自定义的绘制处理函数,功能和继承时的on_draw完全一样 bool handle_draw(const Cairo::RefPtr<Cairo::Context>& cr) { // 这里写你的绘制逻辑,比如画一个红色矩形 cr->set_source_rgb(1.0, 0.0, 0.0); cr->rectangle(10, 10, 100, 100); cr->fill(); return true; } // 示例:处理鼠标点击事件 bool handle_mouse_click(GdkEventButton* event) { if (event->button == 1) { // 左键点击时重绘 m_drawing_area.queue_draw(); } return true; } // 组合的DrawingArea成员 Gtk::DrawingArea m_drawing_area; }; // 主函数中使用自定义类 int main(int argc, char* argv[]) { auto app = Gtk::Application::create(argc, argv, "org.example.customwidget"); Gtk::Window window; window.set_default_size(200, 200); window.set_title("组合式DrawingArea示例"); MyCustomWidget custom_widget; window.add(custom_widget.get_widget()); window.show_all(); return app->run(window); }
这种方式的优势很明显:
- 边界清晰:所有
Gtk::DrawingArea的方法(比如queue_draw()、set_size_request())都必须通过m_drawing_area来调用,而你的自定义方法直接调用,完全不会和基类方法混淆。 - 灵活度高:如果以后需要更换绘制组件(比如换成其他能绘制的Widget),只需要修改类内部的成员变量和信号连接,外部代码几乎不需要改动。
- 符合设计原则:遵循了“组合优于继承”的面向对象设计原则,避免了不必要的继承耦合。
其实Gtkmm的整个信号系统就是为了支持这种非继承式的扩展,官方示例用继承更多是为了简化代码展示,并不代表这是唯一的方式。你完全可以按照这种组合方式来构建你的应用。
内容的提问来源于stack exchange,提问作者Evandro Coan
相关产品推荐
相关产品推荐

