我需要为一个学校项目设计一个一个非常简单的 GUI 框架,它需要支持以下控件/小部件:窗口、面板、图像、标签和按钮。
- 我想到的第一个问题是是否
Window
应该是一个控件。我想应该是这样。 - 我们有
Window
和Panel
其中可以包含其他控件。Button
,Label
和Image
, 不能。所以我们需要两种基本类型的控件;一个是容器,另一个不是(我在 Gtk 实现中看到后者也是一个容器,但只能包含一个子容器。它被称为 GtkBin 。我认为这对我的简单项目来说是一种开销。 - 我遇到的第三个问题是:我需要遍历 UI 树(用于绘图),但由于 C 中没有多态性机制,因此它变得有些问题。
我考虑了以下解决方案,利用 union
。基本上我需要一些函数来转换通用 Control
其实际类型。
typedef struct button {
char *image_path;
} Button;
typedef struct control_node {
Control *node;
struct control_node *next;
} ControlNode;
typedef struct panel {
ControlNode *children;
} Panel;
typedef union control_data {
Panel panel;
Button button;
} ControlData;
typedef struct control {
int x;
int y;
int type;
ControlData *data;
} Control;
因此,我想了解您对我提出的问题的看法以及对我当前策略的看法(我不是在寻找实现方案,而是在寻找想法/想法等)
谢谢。
最佳答案
您应该在每个“GUI 类”的布局中首先放置一个 void *
,它将指向每种类型手动实现的 v-table。每个类型的 v 表中的第一个函数可以是一个,为每个类型返回一个唯一的整数(或者只是一个唯一的整数),因此您可以分辨什么是什么并实现一些类型安全。虽然没有必要,但您可以使用 v-table 指针值来确定类型(因为它将是唯一的),这将节省内存,但会不太明显。在对象销毁中具有虚拟性也很重要,因此用于处理每个唯一类型的内部结构并使其在 v 表中的位置保持一致的析构函数也是必须的。虽然对于您的任务来说这实际上是可以避免的,但对于生产来说这是必须的。
对于实际的树来说,这应该建立在一个简单的父子关系上,围绕着叶子和节点接口(interface),叶子只保存一个指向父节点的指针,节点还包括一个动态列表类型,你还必须实现。那么遍历这棵树就相当简单了。
您可以通过使用“接口(interface)”结构和聚合来代替继承来进行一些模块化,但与单独实现每种类型相比,它不会为您节省太多精力,只要您将 v-table 指针保留在类型布局中的第一个对象,以便您知道您正在使用什么以及如何使用它。其余部分的布局对于遵循任何准则来说并不那么重要,只要您知道类型并将指针转换为适当的结构类型即可。但是由于每个对象都会有一个父对象,甚至是根,可以通过其父对象为 0 来识别它,因此您确实应该将父对象放在 v-table 指针之后,这样您就可以在需要访问的所有内容时避免强制转换父级。
您可以受益的另一件事是使用信号,就像每个按钮中都有另一个指针一样,因此您可以将其分配给“单击”按钮时要执行的函数。
关于c - 用 C 语言设计一个简单的 GUI 框架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31920133/