【问题标题】:When to define a GTK class, when to use signals?何时定义 GTK 类,何时使用信号?
【发布时间】:2012-02-04 00:05:03
【问题描述】:

我对 GTK 还很陌生,正在玩弄我的第一个“严肃”GTK (gtk+-3) 应用程序。我想借鉴其他人的经验,了解何时适合定义新的 GTK 类,或者只使用“普通”GTK 类,并通过信号处理程序实现行为。

到目前为止,我遇到了两个例子:

自定义小部件

我正在创建一个新的小部件:基本上是一个 GtkDrawingArea,我用它来显示一些数据。我最初认为实现这一点的最佳方法是使用G_DEFINE_TYPE 继承 GtkDrawingArea,并提供我自己的绘图回调:

static void mywidget_class_init(MyWidgetClass *klass)
{
    GTK_WIDGET_CLASS(klass)->draw = mywidget_draw;
}

但是,我似乎可以在不定义新类型的情况下实现完全相同的功能,只需创建一个普通的 GtkDrawingArea,并在初始化期间连接适当的信号。

[我的自定义小部件最终将提供的不仅仅是绘图回调,因为它需要是交互式的,但稍后会...]

应用程序窗口

我的应用程序由几个不同的窗口组成,目前是普通的 GtkWindows:

struct myapp_somewindow {
    struct myapp *app;
    GtkWindow    *window;
    GtkWidget    *some_label_that_is_updated;
    /*... other window-specific fields */
}

当 myapp_somewindow 结构初始化时,我使用gtk_window_new() 创建 GtkWindow,并初始化小部件/布局/等,并连接信号。 [我可能最终会使用 .ui 文件来处理更复杂的情况,但窗口现在已经足够简单了。]

这可以通过定义 GtkWindow 的新子类来完成,但我不确定定义新类的代码开销何时变得值得。


我知道对于采用哪种方法可能没有严格的规定,但是在做出这些设计决策时是否有任何通用指南可供使用?这两种方法是否存在任何重大缺陷?

【问题讨论】:

  • gtkforums.com 可能是一个更好的提问地方。我的感觉是,如果你想象它们可能是子类,你应该费心定义你的类。

标签: c oop gtk


【解决方案1】:

我曾使用 GTK+ 和 Clutter 参与过一些项目,并且我一直提倡大量使用通用小部件/actor 的子类化来更具体的小部件/actor。

按照 GObject 的约定,您为每个类创建一个新文件,因此如果您将与您的小部件相关的行为和状态机制拉入一个子类,您将把该代码拉入一个单独的文件中。这有助于更轻松地构建代码,并在其他人想来阅读它时提供帮助。

子类化策略还可以帮助您将封装作为代码库的良好实践。如果您的小部件及其关联的状态和逻辑封装得很好,那么这有助于重用。

使用这种子类化策略的项目的一个很好的例子是任务,特别是它的内部帮助库:http://git.gnome.org/browse/tasks/tree/libkoto 这意味着当我们想要将应用程序移植到新平台或提供不同的视图时数据很容易以不同的方式将现有的小部件和树模型粘合在一起。

如果您想使用 C 并且发现子类化有点乏味,那么您可以试试这个工具:http://git.gnome.org/browse/turbine/ 来帮助您自动创建子类。

【讨论】:

  • 您是否建议对所有内容都使用子类?否则,您对何时不这样做有任何指导方针吗?
  • @Jeremy 不完全是。我建议在您将获得可能可重用组件的地方使用子类化。例如,在顶层和执行实际工作的小部件之间的小部件层次结构中对主要的GtkWindow 或中间框等进行子类化可能没有意义。这也是关于美学 - 如果将这段代码移到它自己的对象和 C 文件中,这会更清楚吗?
  • @RobBradford 感谢涡轮机项目链接。
【解决方案2】:

当您需要为小部件保存一些状态时,我会使用定义新类的指南。否则,您最终将创建包含该状态的自定义结构,以将其作为用户数据传递给信号处理程序,从而使您的代码更加复杂,并为内存泄漏创造更多机会。

这表明对于您的第二个用例,即应用程序窗口,您应该始终定义一个新类。

这样做的一个原因是您的小部件可能一开始很简单,您可以纯粹使用信号处理程序来实现行为,但后来可能会变得更加复杂。例如,假设您想将后备存储添加到您的绘图区域。将您的简单小部件重构为一个类的“感知成本”很高,但它会使您的代码比围绕它工作更干净。

另一个优点是类可以具有属性。您可以将这些属性绑定到其他类的属性或 GSettings 键,这是一种非常强大的机制,可以使您的代码非常简单。

如果您不喜欢所有类样板,请考虑在 Vala 中编程。

【讨论】:

  • 如第二个示例所示(不使用子类),我已经创建了一个结构来包含应用程序窗口的状态 - 它与 GtkWindow 结构具有相同的范围和生命周期我会定义为子类。这种情况下的区别在于结构包含GtkWindow *,而不是嵌入GtkWindow。在后备存储案例中,这两种方法都涉及将后备存储数据添加到该结构。
  • 虽然,我猜子类方法为信号处理程序释放了 gpointer 参数,允许我指定一个指向处理程序的附加指针,因为我可以(我认为)通过其他方式引用小部件。但是,不确定我什么时候需要那个额外的指针。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-01
  • 2014-09-04
  • 1970-01-01
相关资源
最近更新 更多