容器秘密:尺寸分配,第 4 部分

高度随宽度变化

这是我们进入 GTK+ 尺寸分配更深层的地方。高度随宽度变化意味着一个部件不是只有一个最小尺寸,而是它可能会为了获得更大的高度而容纳更小的宽度。大多数部件不是这样的。这种行为的典型例子是一个标签,它可以将其文本换行成多行

  

高度随宽度变化使得尺寸分配更加昂贵,因此容器必须通过设置请求模式来显式启用它。一般来说,容器应该查看它们的子项并使用它们中大多数首选的请求模式。为了简单起见,我们在这里只是硬编码了高度随宽度变化

static GtkSizeRequestMode
gtk_center_box_get_request_mode (GtkWidget *widget)
{
  return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
}

双向测量

编写可以处理高度随宽度变化的 measure() 函数的惯用方法是将其分解为两种情况:一种是沿布局方向测量,另一种是沿相反方向测量。

if (orientation == GTK_ORIENTATION_HORIZONTAL)
  measure_orientation (widget, for_size,
                       orientation,
                       minimum, natural,
                       minimum_baseline, natural_baseline);
else
  measure_opposite (widget, for_size,
                    orientation,
                    minimum, natural,
                    minimum_baseline, natural_baseline);

沿方向测量就像我们一直以来 measure() 函数所做的那样:我们得到一个高度,所以我们询问所有子项对于该高度需要多少宽度,然后我们将答案相加。

沿相反方向测量意味着回答这个问题:给定这个宽度,你需要多少高度? 我们要问子项同样的问题,但是我们应该给每个子项多少宽度? 我们不能只是将完整宽度传递给每个子项,因为我们不希望它们重叠。

分配

为了解决这个问题,我们需要在子项之间分配可用的宽度。这正是我们的 size_allocate() 函数正在做的事情,因此我们需要将 size_allocate() 的内部功能分解到一个单独的函数中。

不出所料,我们将新函数称为 distribute()。

static void
distribute (GtkCenterBox *self,
            int for_size,
            int size,
            GtkRequestedSize *sizes)
{
   /* Do whatever size_allocate() used to do
    * to determine sizes
    */

  sizes[0].minimum_size = start_size;
  sizes[1].minimum_size = center_size;
  sizes[2].minimum_size = end_size;
}

现在我们知道如何获得子项的候选宽度,我们可以完成沿相反方向测量的函数。和之前一样,我们最终返回子项所需高度的最大值,因为我们的布局是水平的。

请注意,在这种情况下,方向是 GTK_ORIENTATION_VERTICAL,因此 gtk_widget_measure() 调用返回的 min 和 nat 值是高度。

distribute (self, -1, width, sizes);

gtk_widget_measure (start_widget,
                    orientation,
                    sizes[0].minimum_size,
                    &start_min, &start_nat,
                    &min_baseline, &nat_baseline);

gtk_widget_measure (center_widget,
                    orientation,
                    sizes[1].minimum_size,
                    &center_min, &center_nat,
                    &min_baseline, &nat_baseline);

gtk_widget_measure (end_widget,
                    orientation,
                    sizes[2].minimum_size,
                    &end_min, &end_nat,
                    &min_baseline, &nat_baseline);

*minimum = MAX (start_min, center_min, end_min);
*natural = MAX (start_nat, center_nat, end_nat);

既然我们现在已经将 size_allocate() 的大部分功能分解到 distribute() 函数中,我们可以直接从那里调用它,然后执行将位置分配给子项的其余必要工作(因为 distribute 已经给了我们大小)。

展开
略低于自然大小
更小
以及更小
以及更小

参考

  1. 容器秘密:尺寸分配
  2. 容器秘密:尺寸分配,第 2 部分
  3. 容器秘密:尺寸分配,第 3 部分
  4. 具有这些更改的代码
  5. 高度随宽度变化的几何管理的文档