label控件存放着字符串,字符串需要的空间会随着容许宽度不同而不同。举个例子,有这么个字符串,一行显示时需要640像素,给它480像素时,须要两行,给它640时,只需要一行。根据容许尺寸的不同来源,有三种方法实现多行文本。注:表中mtwusc是calculate Maximum Text Width Using Same Column control缩写。
使用场景 | width | width_is_max | mtwusc | 实例 |
写脚本时就知道该控件的标称宽度,它将作为容许宽度 | 设置 | false | false | |
写脚本时知道该控件的最大标称宽度,它将作为容许宽度,最终标称宽度会因为内容而变小 | 设置 | true | false | simple_message |
由其它控件算出容许尺寸 | 留空 | false | true |
label控件的height必须留空。前两种都要给控件设置width,实际使用中更多的是要由其它控件决定容许尺寸,即mtwusc=yes时的第三种情况。
“同一列内格子必相同宽度”,网式布局利用这条规则去布局可能多行的文本控件。换句话说,通过同一列的其它格子计算出宽度,然后把这个宽度做为自个容许宽度。基于这个原因,布局逻辑在第一次计算该控件的标称尺寸时,总是返回(0, 0),它要到后面才真正确定尺寸,像放置阶段。在图形化布局时,用以下步骤放置可能多行的文本控件。
- 放置文本控件。打开“标称尺寸”页,使能“mtwuse”。
- 确保有同列的其它控件去计算宽度。
- 如何设置对齐?水平方向、垂直方向都不能用两端对齐。当内容不足一行时,或左对齐、或中央对齐、或右对齐就会影响字符串位置。当所在行有其它控件的高度大于它时,或上对齐、或中央对齐、或下对齐就会影响字符串位置。
一旦使能mtwuse,控件会受到些限制(Studio会执行这些检查)。1)不能出现在树形节点。2)不能设置等尺寸组。3)所在行存在多列时,该列放大系数不能是0。4)滚动面板的孩子有多行文本时,必须把width留空(height通常置0),这是为了一定计算内中mtwuse控件的标称尺寸。
一些gui有个和多行文本相关的控件叫滚动文本框(scroll_label),它是右侧可能会出现垂直滚动条的多行文本。为减少种类,Rose没有做scroll_label,也不做成模板。要实现scroll_label,通常做法是放一个scroll_panel,然后内部一个label。
一、只要前、后宽度不一样,tgrid::require_invalidate_layout就返回true
<librose>/gui/widgets/grid.cpp ------ bool tgrid::require_invalidate_layout(const tcontrol& from) const { ... const tpoint new_best_size = from.calculate_best_size(); const int max_jitter = from.get_text_font_size() * 1 / 3; const int hjitter = new_best_size.x - current_best.x; if (consider_width) { // if (new_best_size.x > current_best.x || posix_abs(hjitter) > max_jitter) { // 改为 if (new_best_size.x != current_best.x) { return true; } } ... }
为什么宽度一有不同就要invalid?——同行可能存在mtwusc控件。确保from控件宽度改变后,就会调用mtwusc控件的tcontrol::set_text_maximum_width,让mtwusc控件“补”上hjitter。

上图这grid有三个控件:icon、input_vars、state。其中input_vars是mtwusc控件。
当state改了label,此时new_best_size.x是90,current_best.x是94,即label宽度由94变成90。相应的,input_vars的text_maximum_width_得从1462变成1466。
二、calculate_col_grow_visible
<librose>/gui/widgets/grid.cpp ------ static std::unique_ptr<bool> calculate_col_grow_visible(const tgrid::tchild* children, int children_vsize, const std::vector<unsigned>& col_grow_factor, unsigned& w_size) { ... for (int at = 0; at < children_vsize; ) { if (children[at].widget_->get_visible() == twidget::INVISIBLE) { at ++; continue; } ptr[at % cols] = true; at ++; if (at % cols == 0) { ... if (all_is_true) { // grid有多行,通过前面行已知道所有列都存在非INVISIBLE控件,没必要遍历后面行了。 break; } } } w_size = 0; for (int at = 0; at < cols; at ++) { if (ptr[at]) { // w_size是那些可见列的grow_factor和 w_size += col_grow_factor[at]; } } return col_grow_visible; }
calculate_col_grow_visible检查各列是存至少个非INVISIBLE控件。要计算两个值。
- w_size是那些可见列的grow_factor和。
- 返回值是个bool数组,每个单元指示一列。true表示该列至少存在一个非INVISIBLE控件。意味着grow_factor不是0时,计算放大时得考虑它。否则,该列都是INVISIBLE控件,计算放大时,不必考虑它。