QT自适应布局中尺寸控制相关的resize、resizeEvent分析

最近开发qt项目,需要QPainter绘图和运行时widget的动态生成,考虑到项目的布局自适应,希望生成的widget控件和绘制的区域都能动态更改大小。因此对控件尺寸、布局管理一顿操作。由于一开始对resize和resizeEvent理解的不到位,走了很多弯路,比如信号与槽机制更新等,最后绕了一圈,还是回到resize和resizeEvent上。因此,在这里梳理一下,记录一下,分享一下。😊

两个关注点

  • 各个控件初始都有被设置成默认尺寸,经debugg测试发现,软件启动时,主窗体和子控件都会被触发一次resizeEvent事件。
  • 使用QPainter绘图,resizeEvent 事件中调用update()函数,会自动触发 paintEvent(QPaintEvent *event)方法。

1、resize函数

在Qt中,resize() 函数用于设置窗口或控件的大小。它是 QWidget 类的一个成员函数,用来动态地改变窗口或控件的大小。
调用该函数后,窗口或控件会立即更新其大小,会自动触发 resizeEvent 事件

2、resizeEvent 事件

resizeEvent 是一个虚拟函数,当窗口或控件的大小发生变化时被调用。在 Qt 的事件处理机制中,每当窗口大小发生变化时,都会生成一个 QResizeEvent 对象,并通过 resizeEvent 函数传递给相应的窗口或控件。

2.1、resizeEvent触发的场景

  1. 控件显示时的初始大小设置:
    当一个控件第一次显示时,其大小会被设置为初始值。这时会触发 resizeEvent。
  2. 控件的大小改变:
    如果控件的大小在运行时发生改变(例如调用了 resize() 函数),就会触发 resizeEvent。
  3. 窗口的大小改变:
    当窗口控件(如 QMainWindow、QDialog)的大小改变时,窗口中的所有子控件的 resizeEvent 会被触发。
  4. 布局管理器调整控件大小:
    如果控件使用了布局管理器(如 QVBoxLayout、QHBoxLayout 等),当父控件的大小改变时,布局管理器会自动调整其管理的子控件的大小,从而触发子控件的 resizeEvent。
  5. 窗口的最大化和最小化:
    当窗口被最大化或最小化时,窗口及其内部的所有控件的大小都会发生变化,从而触发 resizeEvent。
  6. 窗口内容的改变:
    如果控件内部的内容变化导致控件需要重新调整大小,也会触发 resizeEvent。例如,当控件内的文本内容增多导致控件需要扩展以显示全部内容时。
  7. 操作系统或窗口管理器的事件:
    某些情况下,操作系统或窗口管理器可能会发送窗口大小变化的事件,这也会导致 Qt 应用程序中的控件的 resizeEvent 被触发。

3、父子控件关系

子控件(子widget)的大小调整通常是由父控件(父widget)的 resize() 函数或其他导致父控件大小改变的操作来触发的。子控件的 resizeEvent 不需要直接由子控件自身的 resize() 函数来触发,而是依赖于父控件的大小变化,进而影响到子控件的布局和大小。

3.1、如何工作

  1. 父控件的 resize() 函数调用:
  • 当父控件的 resize() 函数被调用时,父控件的大小会立即改变。
  • Qt 的布局管理器(例如 QVBoxLayout、QHBoxLayout 等)通常会捕获父控件大小的变化,并据此调整其管理的子控件的大小和位置。
  1. 子控件的布局管理:
  • 如果子控件使用了布局管理器,布局管理器会响应父控件大小的变化,重新计算并调整子控件的大小和位置。
  • 如果子控件没有使用布局管理器,而是直接在 resizeEvent 中手动调整大小和位置,那么在父控件的 resizeEvent 中重新计算和调整子控件的大小通常是一个良好的做法。
  1. 子控件的 resizeEvent 事件:
  • 当父控件大小变化时,Qt 框架会自动管理子控件的 resizeEvent 事件的触发。
  • 子控件可以重写 resizeEvent 函数以响应其自身大小的变化,通常用于重新绘制内容或调整子控件内部布局。
#include <QtWidgets>

class ChildWidget : public QWidget
{
public:
    ChildWidget(QWidget *parent = nullptr) : QWidget(parent) {}

protected:
    void resizeEvent(QResizeEvent *event) override {
        qDebug() << "ChildWidget resized to:" << event->size();
        QWidget::resizeEvent(event); // 调用父类的resizeEvent处理
    }
};

class ParentWidget : public QWidget
{
public:
    ParentWidget(QWidget *parent = nullptr) : QWidget(parent) {
        QVBoxLayout *layout = new QVBoxLayout(this);
        ChildWidget *childWidget = new ChildWidget(this);
        layout->addWidget(childWidget);
    }

protected:
    void resizeEvent(QResizeEvent *event) override {
        qDebug() << "ParentWidget resized to:" << event->size();
        QWidget::resizeEvent(event); // 调用父类的resizeEvent处理
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    ParentWidget parentWidget;
    parentWidget.resize(400, 300); // 设置初始大小
    parentWidget.setWindowTitle("Parent and Child Resize Example");
    parentWidget.show();

    return app.exec();
}

3.2、特殊情况

如果你的widget是运行时动态创建的,比如widgetA类和widgetB类都继承QWidget类,都设定了布局管理,都是new出来的,A对象当作B对象的容器,当给A进行resize的时候,并没有自动触发B中的resizeEvent事件,而是要对B类对象进行resize才能触发相关事件
项目比较复杂,debugg过程确实进入不到相应断点,没有单独测试,感兴趣的小伙伴自行测试一下。

4、动态创建widget事件绑定

在Qt中,installEventFilter是一个用于将事件过滤器安装到另一个对象的方法。当一个对象安装了事件过滤器后,它会接收到其过滤目标对象的所有事件,并且可以决定是否允许或拒绝这些事件。事件过滤器是Qt事件系统的一部分,用于在事件传播到目标对象之前对其进行拦截和修改。

#include <QApplication>
#include <QWidget>
#include <QMouseEvent>
#include <QEvent>

class EventFilter : public QObject {
    Q_OBJECT
public:
    EventFilter(QObject *parent = nullptr) : QObject(parent) {
        // 创建事件过滤器
    }

protected:
    bool eventFilter(QObject *watched, QEvent *event) override {
        // 过滤目标对象为QWidget
        if (watched == widget) {
            // 过滤事件为鼠标按下事件
            if (event->type() == QEvent::MouseButtonPress) {
                // 处理鼠标按下事件
                QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
                qDebug() << "Mouse button pressed at:" << mouseEvent->pos();
                return true; // 阻止事件传递给目标对象
            }
        }
        return false; // 允许事件传递给目标对象
    }

private:
    QWidget *widget; // 需要安装事件过滤器的QWidget
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建一个QWidget
    QWidget *myWidget = new QWidget();
    myWidget->resize(200, 200);

    // 创建事件过滤器
    EventFilter *eventFilter = new EventFilter();

    // 将事件过滤器安装到QWidget
    myWidget->installEventFilter(eventFilter);

    // 显示QWidget
    myWidget->show();

    return app.exec();
}

  • 35
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Qt,你可以使用布局管理器来实现窗口的自适应分辨率适配。 以下是一个例子: ``` #include <QApplication> #include <QVBoxLayout> #include <QWidget> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; QVBoxLayout *layout = new QVBoxLayout(&window); // 在这里,你可以添加各种控件到布局 window.setLayout(layout); window.show(); return app.exec(); } ``` 使用布局管理器,你可以很容易地实现自动适配,因为它会自动调整控件的大小和位置,以适应窗口的大小变化。 有多种布局管理器可用,如QHBoxLayout、QVBoxLayout、QGridLayout等,你可以根据你的需求选择最合适的布局管理器。 ### 回答2: 在Qt,可以通过使用布局管理器和窗口大小事件来实现窗口自适应分辨率适配。 首先,我们可以选择适合自己的布局管理器,如垂直布局(QVBoxLayout)或水平布局(QHBoxLayout),以便自动调整窗口的控件位置和大小。 然后,我们需要在窗口的构造函数设置布局管理器,并将所有的控件添加到布局管理器。如下所示: ```cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QVBoxLayout *layout = new QVBoxLayout; // 创建垂直布局管理器 QLabel *label = new QLabel("Hello, World!"); // 创建标签控件 layout->addWidget(label); // 将标签控件添加到布局管理器 QPushButton *button = new QPushButton("Submit"); // 创建按钮控件 layout->addWidget(button); // 将按钮控件添加到布局管理器 QWidget *centralWidget = new QWidget(this); // 创建一个主窗口控件 centralWidget->setLayout(layout); // 设置布局管理器为主窗口控件的布局 setCentralWidget(centralWidget); // 设置主窗口控件为窗口的央控件 } ``` 接下来,需要监听窗口的大小事件,以便在窗口大小改变时重新布局控件。可以重写窗口类的`resizeEvent`函数,并在其重新设置布局管理器的大小。如下所示: ```cpp void MainWindow::resizeEvent(QResizeEvent *event) { QMainWindow::resizeEvent(event); // 调用基类的 resizeEvent 函数 // 获取新的窗口大小 QSize newSize = event->size(); // 更新布局管理器的大小 centralWidget()->layout()->setGeometry(QRect({0, 0}, newSize)); } ``` 通过上述步骤,窗口的控件将会根据窗口的大小自动进行适配和调整。无论用户在不同的分辨率下打开窗口,控件都会根据界面的实际大小进行自适应。 这就是使用Qt实现窗口自适应分辨率适配的基本步骤。根据具体的需求,可以进一步调整布局管理器和控件的属性,以达到理想的自适应效果。 ### 回答3: 在Qt,可以通过以下几个步骤来实现窗口自适应分辨率适配: 1. 获取当前屏幕的分辨率信息:可以使用QApplication类的primaryScreen()函数获取主屏幕的信息,然后使用QScreen类的geometry()函数获取屏幕的几何信息,包括宽度和高度。 2. 设置窗口大小:根据获取到的屏幕信息,可以设置窗口的初始大小。可以使用QWidget类的resize()函数设置窗口的宽度和高度,例如:widget->resize(screenGeometry.width() / 2, screenGeometry.height() / 2)。 3. 设置窗口位置:可以使用QWidget类的move()函数设置窗口的初始位置,通常将窗口居显示。可以通过计算得到窗口在屏幕上的心位置,例如:widget->move(screenGeometry.center() - widget.rect().center())。 4. 设置窗口的最大化和最小化策略:可以使用QWidget类的setWindowFlags()函数设置窗口的标志位,实现最大化和最小化功能。可以使用Qt::WindowMaximize和Qt::WindowMinimize标志位来实现最大化和最小化功能。 5. 监听窗口大小变化事件:可以通过重写QWidget类的resizeEvent()函数来监听窗口大小变化事件,根据实际需要做出相应的布局调整。 通过以上步骤,就可以实现窗口的自适应分辨率适配。在程序启动时,窗口将根据屏幕的分辨率设置初始大小和位置,并可以根据窗口大小的变化做出相应的布局调整,以适应不同分辨率的屏幕。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值