我最近有机会为支持 GTK+ 所有功能的容器重新实现尺寸分配。
- RTL 支持
- 自然尺寸
- 对齐和展开
- 高度随宽度变化
- 方向支持
- 基线
如果您在应用程序中进行一次性容器,则其中大多数可能无关紧要,但在通用的 GTK+ 小部件中,它们迟早都可能会变得相关。
由于要涵盖的内容很多,因此需要几篇文章才能完成。 让我们开始吧!
起点
GtkCenterBox 是一个简单的小部件,可以包含三个子小部件 - 它不是一个 GtkContainer,至少目前不是。 在 GTK+ 4 中,任何小部件都可以是其他小部件的父级。 GtkCenterBox 应用于其子项的布局是将中间子项居中,只要有可能。 这是 GtkBox 在 GTK+ 3 中提供的功能,但中间子项处理使已经复杂的容器更加复杂。 因此,我们将其移动到 GTK+ 4 中的一个单独的小部件中。




当我开始查看 GtkCenterBox 尺寸分配代码时,它非常简单。 要查看的两个方法是 measure() 和 size_allocate()。
measure 实现只是测量三个子项,在水平方向上将最小尺寸和自然尺寸相加,并在垂直方向上取它们的最大值。 大致伪代码如下:
if (orientation == GTK_ORIENTATION_HORIZONTAL) { *minimum = child1_min + child2_min + child3_min; *natural = child1_nat + child2_nat + child3_nat; } else { *minimum = MAX(child1_min, child2_min, child3_min); *natural = MAX(child1_min, child2_min, child3_min); }
size_allocate 实现是将第一个子项放在左侧,最后一个子项放在右侧,然后将中间子项放在中心,通过根据需要将其向右或向左推来消除重叠。
child1_width = child1_min; child2_width = child2_min; child3_width = child3_min; child1_x = 0; child3_x = total_width - child3_width; child2_x = total_width/2 - child2_width/2; if (child2_x < child1_x + child1_width) child2_2 = child1_x + child1_width; else if (child2_x + child2_width > child3_x) child2_x = child3_x - child2_width;
如您所见,这非常简单。 可惜的是,它没有任何我上面列出的功能。
- 子项始终获取其最小尺寸
- 未考虑 ::expand 属性
- 无论文本方向如何,第一个子项始终放置在左侧
- 没有垂直方向
- 不支持高度随宽度变化
- 基线被忽略
在接下来的几篇文章中,我将尝试展示如何将这些功能添加回来,希望能在此过程中澄清 GTK+ 尺寸分配工作原理的一些奥秘。
关于“容器秘密:尺寸分配”的一个想法
评论已关闭。