QT sizeHint 及 Policy的用法

本文详细解析了Qt中sizeHint、minimumSizeHint与sizePolicy属性的功能与用法,并通过实例演示了这些属性如何影响窗口和控件的尺寸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


    Qt 中的 sizeHint 属性,sizeHint() 如何使用?
    Qt 中的 minimumSizeHint 属性,minimumSizeHint() 如何使用?
    Qt 中的 sizePolicy 属性,setSizePolicy()、sizePolicy()如何使用?

        之前一直对这几个属性搞不清楚,前几天仔仔细细地看了文档解释并做了一些测试,现在来归纳一下:

        首先我们得知道这几个属性保存的值是什么,它们分别是用来干什么的。

      sizeHint
    [From Qt Doc: This property holds the recommended size for the widget. If the value of this property is an invalid size, no size is recommended. The default implementation of sizeHint() returns an invalid size if there is no layout for this widget, and returns the layout's preferred size otherwise. ] 这个属性所保存的 QSize 类型的值是一个被推荐给窗口或其它组件(为了方便下面统称为widget)的尺寸,也就是说一个 widget 该有多大,它的一个参考来源就是这个 sizeHint 属性的值,而这个值由 sizeHint() 函数来确定。但是 widget 的大小的确定还有其它因素作用,下面会讲到。现在只需知道 sizeHint() 会返回一个被推荐的尺寸。那么这个尺寸的取值是怎样的呢?当它是一个无效值的时候(sizeHint().isValid() 返回 false,QSize 中 width 或者 height 有一个为复数就会是无效的),什么作用也没有;当它是一个有效值的时候,它就成了 widget 大小的一个参考。Qt 中对 sizeHint() 的默认实现是这样的:当 widget 没有布局(layout),返回无效值;否则返回其 layout 的首选尺寸(preferred size)。

       1: QWidget *widget = new QWidget;

       2: widget->show();

       3: qDebug() << widget->width() << "," << widget->height();

       4: qDebug() << widget->sizeHint().width() << "," << widget->sizeHint().height();

       1: //output:

       2: //1009 , 520

       3: //-1 , –1

    输出结果中第二行:sizeHint() 返回的是一个无效的 QSize,因为 widget 没有布局。

       1: QWidget *widget = new QWidget;

       2: QHBoxLayout *layout = new QHBoxLayout;

       3: QPushButton *button = new QPushButton("Ggicci");

       4: layout->addWidget(button);

       5: widget->setLayout(layout);

       6: widget->show();

       7: qDebug() << widget->width() << "," << widget->height();

       8: qDebug() << widget->sizeHint().width() << "," << widget->sizeHint().height();

       9: qDebug() << button->width() << "," << button->height();

    2012-10-26_1729

       1: //output:

       2: //112 , 45

       3: //97 , 45

       4: //90 , 23

    输出结果中第一行:widget 的实际尺寸 (112, 45);
    输出结果中第二行:sizeHint() 返回 layout 的首选尺寸(97,45)供 widget 参考;
    输出结果中第三行:中间 button 的实际大小;
    从输出结果中可以证明以上说过的两点:

        1) 在 widget 有 layout 的情况下,其 sizeHint() 函数返回的是有效值作为其自身实际尺寸的参考;
        2) sizeHint() 返回的值并不一定会作为 widget 的实际尺寸,因为 widget 的尺寸的决定还有其它因素作用;

      minimumSizeHint
    [From Qt Doc: This property holds the recommended minimum size for the widget. If the value of this property is an invalid size, no minimum size is recommended. The default implementation of minimumSizeHint() returns an invalid size if there is no layout for this widget, and returns the layout's minimum size otherwise. Most built-in widgets reimplement minimumSizeHint().] Qt 中的 widget 有 size 和 minimumSize 两个属性,比较好理解的是上面的 sizeHint 是作为 size 的参考的,那么 minimumSizeHint 是作为 minimumSize 的参考的。minimumSizeHint() 的默认实现同 sizeHint() 基本一样:在 widget 无 layout 的情况下返回无效值;否则返回 layout 的最小尺寸(minimum size),注意与上面的首选尺寸不同哦!有同学会问 preferred size 和 minimum size 的区别:preferred size 由 layout 的 sizeHint() 函数返回,minimum size 由 layout 的 minimumSize() 函数返回;前者的实现会根据 layout 的种类的变化而变化,比如在 QHBoxLayout 和 QVBoxLayout 中各放置同样的两个 QPushButton,两者的 sizeHint() 返回的值是不一样的,后者是返回能够容纳下所有包含在 layout 内的组件的最小尺寸。Qt 中大多数内置的 widget 都已经重新实现了 minimumSizeHint()。你可以自己写自己的 widget 然后重新实现 sizeHint()、minimumSizeHint() 这些函数来达到自己的布局效果。
    [From Qt Doc: QLayout will never resize a widget to a size smaller than the minimum size hint unless minimumSize() is set or the size policy is set to QSizePolicy::Ignore. If minimumSize() is set, the minimum size hint will be ignored.] layout 永远也不会把一个 widget 的大小设置到比 minimumSizeHint() 返回的尺寸还小,除非 widget 设置了最小尺寸或者其 sizePolicy 属性设置了 QSizePolicy::Ignore。如果 widget 通过 setMinimumSize() 设置了最小尺寸,那么 minimumSizeHint 的作用就会被忽略掉。我们知道如果在一个 layout 里面添加一些子 widget,然后窗口应用这个 layout 的时候,一般情况下我们是无法缩放到使其中的子 widget 看不见的。如下:

       1: QWidget *widget = new QWidget;

       2: widget->setMinimumSize(10, 10);

       3: QVBoxLayout *layout = new QVBoxLayout;

       4: QPushButton *button = new QPushButton("Ggicci");

       5: layout->addWidget(button);

       6: widget->setLayout(layout);

       7: widget->show();

    这里同上显示一个含有 QPushButton 的 QWidget,不过在这里设置了其最小尺寸为(10, 10),此时 minimumSizeHint() 将不起作用,也就是我们可以把 widget 缩放到(10, 10),不过这是理论上的哦,亲~(在这里你讲看到一个例外),以下就是缩小到了极致:(112,10),同学,是否在思考为什么 width 无法缩小到比  112 更小了。其实这是 widget 和 windows 系统的共同问题,第一 widget 默认有 min,max,close 三个按钮,也就是右上角的最小化、最大化、关闭按钮,这导致了 width 无法继续缩小。其实通过 widget->setWindowFlags(Qt::Window | Qt::WindowTitleHint); 可以把 min, max 按钮给去了,这样的 widget 的 width 就可以比之前更小一点啦,如下右图。
    2012-10-26_18192012-10-26_1837

      sizePolicy
    [From Qt Doc: This property holds the default layout behavior of the widget. If there is a QLayout that manages this widget's children, the size policy specified by that layout is used. If there is no such QLayout, the result of this function is used.] 这个属性保存了该 widget 的默认布局属性,如果它有一个 layout 来布局其子 widgets,那么这个 layout 的 size policy 将被使用;如果该 widget 没有 layout 来布局其子 widgets,那么它的 size policy 将被使用。默认的 policy 是 Preferred/Preferred。QSizePolicy::Policy 枚举值有如下几个:

    Constants
     

    Description
    QSizePolicy::Fixed  widget 的实际尺寸只参考 sizeHint() 的返回值,不能伸展(grow)和收缩(shrink)
    QSizePolicy::Minimum  可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能缩小到的最小尺寸
    QSizePolicy::Maximum  可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能伸展到的最大尺寸
    QSizePolicy::Preferred  可以伸展和收缩,但没有优势去获取更大的额外空间使自己的尺寸比 sizeHint() 的返回值更大
    QSizePolicy::Expanding  可以伸展和收缩,它会尽可能多地去获取额外的空间,也就是比 Preferred 更具优势
    QSizePolicy::MinimumExpanding  可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能缩小到的最小尺寸,同时它比 Preferred 更具优势去获取额外空间
    QSizePolicy::Ignored  忽略 sizeHint() 的作用

    Y8IDK

从上图中可以看出 Preferred 虽然可以收缩得比 sizeHint() 更小,但是最小由 minimumSizeHint() 限制

        QSizePolicy::Fixed

       1: QWidget *widget = new QWidget;

       2: QHBoxLayout *layout = new QHBoxLayout;

       3: QPushButton *button = new QPushButton("Ggicci");

       4: //button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

       5: layout->addWidget(button);

       6: widget->setLayout(layout);

       7: widget->show();

    在第4行代码注释掉的情况下:QPushButton 默认的 sizePolicy 是垂直方向 Fixed,水平方向 Preferred,故水平方向会伸展2012-10-26_2030
    没有注释掉的情况下:
    2012-10-26_2035
    
        QSizePolicy::Preferred 和 QSizePolicy::Expanding 的区别:两者都可以伸展和收缩,但是区别在于谁可以伸展地更牛B

       1: QWidget *widget = new QWidget;

       2: QHBoxLayout *layout = new QHBoxLayout;

       3: QPushButton *button1 = new QPushButton("Ggicci");

       4: QPushButton *button2 = new QPushButton("Mingjie Tang");

       5: button1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

       6: button2->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

       7: layout->addWidget(button1);

       8: layout->addWidget(button2);

       9: widget->setLayout(layout);

      10: widget->show();

    两者一样牛B(在水平方向上,垂直方向不构成额外空间竞争关系):
    2012-10-26_2042

       1: QWidget *widget = new QWidget;

       2: QHBoxLayout *layout = new QHBoxLayout;

       3: QPushButton *button1 = new QPushButton("Ggicci");

       4: QPushButton *button2 = new QPushButton("Mingjie Tang");

       5: button1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

       6: button2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

       7: layout->addWidget(button1);

       8: layout->addWidget(button2);

       9: widget->setLayout(layout);

      10: widget->show();

    button2更牛B(在水平方向上构成竞争关系):
    2012-10-26_2047
        有了上述的样例,QSizePolicy::Minimum, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored 就比较好理解了吧,亲

<think>我们正在讨论Qt中的PolicyFlag。根据用户的问题,他们想了解PolicyFlag的用法和实现细节。首先,我们需要明确PolicyFlag是什么。在Qt中,PolicyFlag通常与大小策略(QSizePolicy)相关,用于控制布局中widget的大小行为。然而,用户提到的“PolicyFlag”可能是一个泛指,或者是指特定控件中的标志(如QSizePolicy::Policy枚举或某些策略标志)。由于没有直接名为“PolicyFlag”的类或枚举,我们需要推断用户可能指的是什么。 根据Qt文档,QSizePolicy类定义了widget在布局管理中的大小策略。它包含水平和垂直两个方向的大小策略,每个方向由QSizePolicy::Policy枚举值控制,这些枚举值包括: - QSizePolicy::Fixed:widget不能改变大小,只使用sizeHint()的大小。 - QSizePolicy::Minimum:sizeHint()是最小大小,widget可以扩展,但变大没有优势(不会变得比最小大小更小)。 - QSizePolicy::Maximum:sizeHint()是最大大小,widget可以缩小到最小大小(minimunSize),但不能变大超过sizeHint()。 - QSizePolicy::Preferred:sizeHint()是最佳大小,widget可以缩小到最小大小,也可以扩展,但没有优势。 - QSizePolicy::Expanding:widget可以缩小到最小大小,也可以扩展,并且会尽可能利用空间。 - QSizePolicy::MinimumExpanding:sizeHint()是最小大小,widget可以扩展,并且会尽可能利用空间。 - QSizePolicy::Ignored:忽略sizeHint(),widget会尽可能占据空间(相当于Expanding,但忽略sizeHint)。 此外,QSizePolicy还包含一些标志,如控制大小约束的ControlType(例如,按钮、复选框等)和设置是否保留空间当隐藏等。 因此,我们假设用户所说的“PolicyFlag”指的是这些策略枚举值或QSizePolicy的使用。 下面,我们将介绍QSizePolicy用法和实现细节。 ### QSizePolicy用法 #### 设置大小策略 在Qt中,可以通过`QWidget::setSizePolicy`方法为widget设置大小策略。例如: ```cpp // 创建一个按钮 QPushButton *button = new QPushButton("Click me"); // 设置水平策略为Fixed,垂直策略为Expanding button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); ``` 也可以使用QSizePolicy对象: ```cpp QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); policy.setHorizontalStretch(1); // 设置水平拉伸因子 policy.setVerticalStretch(0); // 设置垂直拉伸因子 button->setSizePolicy(policy); ``` #### 获取大小策略 通过`QWidget::sizePolicy()`方法可以获取当前widget的大小策略。 #### 在布局中的行为 布局管理器(如QHBoxLayout, QVBoxLayout, QGridLayout)在计算布局时,会考虑每个widget的大小策略。例如,一个具有Expanding策略的widget会占据多余的空间,而Fixed策略的widget则保持固定大小。 ### 实现细节 QSizePolicy类内部使用一个整数(quint32)来存储策略信息。其中低4位用于水平策略,接下来的4位用于垂直策略,其余位用于存储其他标志(如控制类型、是否保留空间等)。 在布局过程中,布局管理器会调用每个widget的`sizeHint()`、`minimumSizeHint()`以及`sizePolicy()`来决定如何分配空间。 ### 示例:使用QSizePolicy控制布局行为 假设我们有两个按钮,一个我们希望它固定大小,另一个我们希望它扩展以填充空间。 ```cpp #include <QApplication> #include <QPushButton> #include <QHBoxLayout> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; QHBoxLayout *layout = new QHBoxLayout(&window); QPushButton *button1 = new QPushButton("Fixed"); button1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); button1->setFixedSize(100, 50); // 固定大小,但注意设置固定大小会覆盖Fixed策略 QPushButton *button2 = new QPushButton("Expanding"); button2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); layout->addWidget(button1); layout->addWidget(button2); window.show(); return app.exec(); } ``` 注意:如果同时设置了固定大小(setFixedSize)和大小策略,固定大小会覆盖策略。因此,在设置Fixed策略时,通常不需要再设置固定大小,因为Fixed策略会使用sizeHint()作为固定大小。但可以通过setFixedSize覆盖。 ### 其他策略标志 QSizePolicy还提供了一些额外的标志,例如: - `setRetainSizeWhenHidden(bool)`:当widget隐藏时,布局是否保留其空间。 - `setControlType(ControlType)`:指定控件的类型,以便布局管理器进行特殊处理(例如,单选按钮组)。 ### 注意事项 - 在自定义widget时,需要重写`sizeHint()`和`minimumSizeHint()`以返回合适的大小,这样大小策略才能正确工作。 - 拉伸因子(setHorizontalStretch和setVerticalStretch)可以影响在布局中多余空间的分配比例。 ### 引用说明 在Qt文档中,QSizePolicy的详细说明可以参考[QSizePolicy Class](https://doc.qt.io/qt-6/qsizepolicy.html)。 [^1]: [QLibrary Class | Qt Core 6.7.0](https://doc.qt.io/qt-6/qlibrary.html) [^2]: [Qt Quick Controls 2: QML Types](https://doc.qt.io/qt-6/qtquickcontrols2-qmlmodule.html) [^3]: [Qt Graphical Effects: MultiEffect](https://doc.qt.io/qt-6/qtgraphicaleffects-multieffect.html) §§相关问题§§ 1. Qt中QSizePolicy::Policy有哪些枚举值?它们分别代表什么含义? 2. 如何在QML中设置控件的大小策略? 3. 自定义控件时,如何正确实现sizeHint()和minimumSizeHint()? 4. 布局管理器是如何根据大小策略计算布局的?</think>### Qt PolicyFlag 使用与实现详解 在 Qt 中,`PolicyFlag` 通常指大小策略相关的枚举标志,主要用于控制控件在布局中的尺寸行为。核心类是 `QSizePolicy`,它通过水平和垂直方向的策略组合,定义控件如何响应布局空间变化。 #### 一、核心策略枚举值 `QSizePolicy::Policy` 包含以下常用标志: ```cpp // 水平/垂直策略枚举 QSizePolicy::Fixed // 固定为 sizeHint() 大小 QSizePolicy::Minimum // sizeHint() 为最小值,可扩展 QSizePolicy::Maximum // sizeHint() 为最大值,可收缩 QSizePolicy::Preferred // sizeHint() 为最佳大小,可伸缩 QSizePolicy::Expanding // 尽可能扩展,与其他 Expanding 控件共享空间 QSizePolicy::Ignored // 忽略 sizeHint(),尽可能占据空间 ``` #### 二、基本使用方法 1. **设置控件策略** ```cpp QPushButton *button = new QPushButton("Click"); // 水平固定 + 垂直扩展 button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); ``` 2. **组合策略与高级配置** ```cpp QSizePolicy policy; policy.setHorizontalPolicy(QSizePolicy::Preferred); policy.setVerticalPolicy(QSizePolicy::Minimum); policy.setRetainSizeWhenHidden(true); // 隐藏时保留布局空间 policy.setHorizontalStretch(2); // 水平拉伸因子 label->setSizePolicy(policy); ``` 3. **在布局中的行为** - `Expanding` 控件优先扩展 - `Fixed` 控件保持固定尺寸 - 拉伸因子(Stretch)控制扩展比例,例如: ```cpp layout->addWidget(widget1, 1); // 占比1/3 layout->addWidget(widget2, 2); // 占比2/3 ``` #### 三、实现原理 1. **布局计算流程** - 布局管理器收集所有控件的 `sizeHint()` 和 `minimumSizeHint()` - 根据策略计算初始空间分配 - 对剩余空间按策略优先级分配: ```mermaid graph TD A[可用空间] --> B{Expanding控件?} B -->|是| C[按拉伸因子分配] B -->|否| D[分配给Minimum/Preferred] ``` 2. **策略优先级** - `Expanding` > `Preferred` > `Minimum` - `Fixed` 始终不扩展 - `Ignored` 会覆盖 `sizeHint()` 约束 #### 四、特殊场景处理 1. **隐藏控件保留空间** ```cpp policy.setRetainSizeWhenHidden(true); // 避免布局抖动 ``` 2. **透明窗口策略** 结合透明窗口标志使用(参考引用[^2]): ```cpp QSurfaceFormat format; format.setAlphaBufferSize(8); // 透明通道 view->setFormat(format); view->setColor(Qt::transparent); ``` 3. **动态策略切换** ```cpp // 响应屏幕旋转 void onOrientationChanged() { if (landscape) widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); else widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); } ``` #### 五、最佳实践 1. **优先使用布局管理器** 而非固定尺寸 2. **自定义控件必须实现**: ```cpp QSize MyWidget::sizeHint() const { return QSize(200, 100); // 返回合理默认尺寸 } ``` 3. **避免策略冲突**: - 不要同时设置 `setFixedSize()` 和 `Expanding` 策略 - 嵌套布局时注意拉伸因子传递 > 引用说明:Qt 策略系统设计参考了 GUI 布局的经典模型[^1],透明窗口实现关联 QSurfaceFormat 配置[^2],现代 Qt 6 推荐使用官方布局方案替代传统方法[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值