美文网首页
重载resizeEvent

重载resizeEvent

作者: downdemo | 来源:发表于2018-09-20 17:16 被阅读12次

简单实现

  • 目标:改变窗口大小时,窗口中的控件布局将相应改变。如:窗口中包含两个QPushButton控件,宽度小于400时,两个按钮垂直排列,宽度拉伸不低于400时,两个按钮则变为垂直排列;
  • 方法:重载resizeEvent;
  • Widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QMainWindow>
#include "qpushbutton.h"
#include "qboxlayout.h"

namespace Ui {
    class Form;
}

class widget : public QMainWindow
{
    Q_OBJECT

public:
    explicit widget(QWidget *parent = 0);
    ~widget();

private:
    Ui::Form *ui;

    QVBoxLayout* layout;
    QHBoxLayout* layout2;
    QPushButton* btn1;
    QPushButton* btn2;
    QWidget* centralWidget;

protected:
    void resizeEvent(QResizeEvent* event);
};

#endif // WIDGET_H
  • Widget.cpp
#include "Widget.h"
#include "ui_Widget.h"

widget::widget(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);

    btn1 = new QPushButton;
    btn1->setText("1");
    btn2 = new QPushButton;
    btn2->setText("2");
    centralWidget = new QWidget;
    setCentralWidget(centralWidget);
}

widget::~widget()
{
    delete ui;
}

void widget::resizeEvent(QResizeEvent* event)
{
    int w = width();
    if (w < 400)
    {
        if (centralWidget->layout()) delete centralWidget->layout();
        QVBoxLayout* layout = new QVBoxLayout;
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        centralWidget->setLayout(layout);
    }
    else
    {
        if (centralWidget->layout()) delete centralWidget->layout();
        QHBoxLayout* layout2 = new QHBoxLayout;
        layout2->addWidget(btn1);
        layout2->addWidget(btn2);
        centralWidget->setLayout(layout2);
    }
}

实现效果

宽度低于400应用垂直布局 否则应用水平布局

存在问题

  • 当窗口尺寸不低于400,点击最大化和还原不会改变布局(正常预期)
最大化后布局不变
  • 但当窗口尺寸低于400,按钮纵向排列,点击最大化之后按钮仍纵向排列(预期是窗口不低于400宽度则横向排列)
最大化后布局不变
  • 再次点击还原,布局却又变为横向排列(预期是窗口低于400宽度则纵向排列)
还原后布局却改变
  • 不断点击最大化和还原则将重复上述两种情况,直到拖动窗口大小时又会变为正常情况

改进

  • 通过qDebug测试,最大化和还原都正确触发了事件
void widget::resizeEvent(QResizeEvent* event)
{
    int w = width();
    if (w < 400)
    {
        if (centralWidget->layout())
        {
            delete centralWidget->layout();
            qDebug() << "d1";
        }
        QVBoxLayout* layout = new QVBoxLayout;
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        centralWidget->setLayout(layout);
        qDebug() << "aaa";
    }
    else
    {
        if (centralWidget->layout())
        {
            delete centralWidget->layout();
            qDebug() << "d2";
        }
        QHBoxLayout* layout2 = new QHBoxLayout;
        layout2->addWidget(btn1);
        layout2->addWidget(btn2);
        centralWidget->setLayout(layout2);
        qDebug() << "bbb";
    }
}
  • 虽然找不出原因,但可以换个思路绕过此问题,不选择delete布局,而是直接new新的QWidget
// file "Widget.cpp"

#include "Widget.h"
#include "ui_Widget.h"

widget::widget(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);

    btn1 = new QPushButton;
    btn1->setText("1");
    btn2 = new QPushButton;
    btn2->setText("2");
}

widget::~widget()
{
    delete ui;
}

void widget::resizeEvent(QResizeEvent* event)
{
    int w = width();
    // centralWidget = new QWidget;
    if (w < 400)
    {
        QVBoxLayout* layout = new QVBoxLayout;
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        centralWidget = new QWidget; // 也可以在if else判断之前new
        centralWidget->setLayout(layout);
        setCentralWidget(centralWidget); // 也可以在if else之后设置
    }
    else
    {
        QHBoxLayout* layout2 = new QHBoxLayout;
        layout2->addWidget(btn1);
        layout2->addWidget(btn2);
        centralWidget = new QWidget;
        centralWidget->setLayout(layout2);
        setCentralWidget(centralWidget);
    }
    // setCentralWidget(centralWidget);
}
  • 现在最大化和还原将达到预期效果
宽度低于400应用垂直布局 最大化后如预期应用水平布局 还原后恢复垂直布局

加入滚动条

  • 目标:当控件超出窗口大小时,需要提供滚动条,否则控件将缩小并排满窗口。如:窗口中包含10张表格,每张表格高度至少为300,当窗口宽度小于800时,表格垂直排列,不低于800时则水平排列;
  • 方法:使用QScrollArea设置一片带滚动条的区域,这个区域是空的,还需要用setWidget添加一个控件,setWidget只能添加一个控件,如果多次使用只保留最后的设置,若之前setWidget的控件未释放则将成为悬挂指针。在处理上面举例的多个控件问题时,setWidget添加的应该是一个QWidget,QTableWidget添加到layout后,再对QWidget使用setLayout,即QMainWindow - QScrollArea - QWidget - QLayout - QTableWidget
  • 注意:在setWidget之前,必须给QWidget添加layout,否则将不显示widget,只显示一片空的滚动条区域。并且必须使用QMainWindow作为主窗口,因为QWidget没有setCentralWidget的功能,将出现无法显示滚动条的问题!
scrollArea = new QScrollArea;
centralWidget = new QWidget;
layout = new QVBoxLayout;
... // 设置layout
// layout->setSizeConstraint(QLayout::SetFixedSize);
centralWidget->setLayout(layout);
scrollArea->setWidget(centralWidget);
setCentralWidget(scrollArea);
不显示控件的QScrollArea
  • 因为setCentralWidget方法只能使用一次,所以仍要写在构造函数中,此时的中心控件是QScrollArea
  • layout是写在resizeEvent中的,为QWidget setLayout和为QScrollArea setWidget必须连写在一起,因此两者也要写在resizeEvent中
  • QWidget必须在resizeEvent中new,若在构造函数中new,则会出现溢出
  • QScrollArea只需要声明一次,使用时不需要销毁,因此最好在构造函数中new,若在resizeEvent中new,则会在改变窗口大小时出现闪屏现象(每次改动窗口都要重新new一个新的QScrollArea)
  • 可以通过样式改变QScrollArea的背景色
scrollArea->setStyleSheet("background-color:transparent;"); // 透明背景:所有子控件也会受影响
scrollArea->viewport()->setStyleSheet("background-color:transparent;"); // 这句实测无效

详细实现

  • Widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QMainWindow>
#include "qpushbutton.h"
#include "qboxlayout.h"
#include "qscrollarea.h"
#include "qtablewidget.h"

namespace Ui {
    class Form;
}

class widget : public QMainWindow
{
    Q_OBJECT

public:
    explicit widget(QWidget *parent = 0);
    ~widget();

private:
    Ui::Form *ui;

    QVBoxLayout* layout;
    QHBoxLayout* layout2;
    QPushButton* btn1;
    QPushButton* btn2;
    QWidget* centralWidget;
    QScrollArea* scrollArea;
    QTableWidget* table1;
    QTableWidget* table2;

protected:
    void resizeEvent(QResizeEvent* event);
};

#endif // WIDGET_H
  • Widget.cpp
#include "Widget.h"
#include "ui_Widget.h"

widget::widget(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);

    centralWidget = new QWidget;

    btn1 = new QPushButton;
    btn1->setText("1");
    btn2 = new QPushButton;
    btn2->setText("2");
    table1 = new QTableWidget(20, 10, 0);
    table2 = new QTableWidget(20, 10, 0);
    table1->setMinimumHeight(200); // 表格设置最小高度
    table2->setMinimumHeight(200);

    for(int i = 0; i < 20; ++i)
        for (int j = 0; j < 10; ++j)
        {
            QTableWidgetItem* item = new QTableWidgetItem;
            QTableWidgetItem* item2 = new QTableWidgetItem;
            QString txt = QString("%1%2").arg(i).arg(j);
            QString txt2 = QString("%1%2").arg(j).arg(i);
            item->setText(txt);
            item2->setText(txt2);
            table1->setItem(i, j, item);
            table2->setItem(i, j, item2);
        }
  
    scrollArea = new QScrollArea;
    setCentralWidget(scrollArea);
}

widget::~widget()
{
    delete ui;
}

void widget::resizeEvent(QResizeEvent* event)
{
    int w = width();
    if (w < 400)
    {
        QVBoxLayout* layout = new QVBoxLayout;
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        layout->addWidget(table1);
        layout->addWidget(table2);
        centralWidget = new QWidget; // 必须在此处创建
        centralWidget->setLayout(layout);
        scrollArea->setWidget(centralWidget);
    }
    else
    {
        QHBoxLayout* layout2 = new QHBoxLayout;
        layout2->addWidget(btn1);
        layout2->addWidget(btn2);
        layout2->addWidget(table1);
        layout2->addWidget(table2);
        centralWidget = new QWidget;
        centralWidget->setLayout(layout2);
        scrollArea->setWidget(centralWidget);
    }
}

实现效果

宽度低于400控件垂直排列 否则水平排列

设置控件大小

可以使用setFixedSize为每个控件指定固定尺寸,也可以用setMinimumSize、setMaximumSize设置最小、最大尺寸,或者用setFixedHeight、setFixedWidth、setMinimumHeight、setMinimumWidth、setMaximumHeight、setMaximumWidth单独设置高度或宽度。在构造函数中或resizeEvent中设置均可,若不根据窗口大小变化则在构造函数中设置,若需要变化则在resizeEvent中设置。

void widget::resizeEvent(QResizeEvent* event)
{
    int w = width();
    if (w < 400)
    {
        QVBoxLayout* layout = new QVBoxLayout;
        btn1->setFixedSize(100, 50);
        btn2->setFixedSize(50, 100);
        layout->addWidget(btn1);
        layout->addWidget(btn2);
        layout->addWidget(table1);
        layout->addWidget(table2);
        centralWidget = new QWidget;
        centralWidget->setLayout(layout);
        scrollArea->setWidget(centralWidget);
    }
    else
    {
        QHBoxLayout* layout2 = new QHBoxLayout;
        btn1->setFixedSize(50, 100);
        btn2->setFixedSize(100, 50);
        layout2->addWidget(btn1);
        layout2->addWidget(btn2);
        layout2->addWidget(table1);
        layout2->addWidget(table2);
        centralWidget = new QWidget;
        centralWidget->setLayout(layout2);
        scrollArea->setWidget(centralWidget);
    }
}
宽度低于400 宽度不低于400

拖动中间边线同时改动左右窗口大小

  • 目标:主窗口分为左右两部分,按下鼠标拖动中间的边框线可以减小(增大)左窗口宽度,同时增大(减小)右窗口宽度
  • 方法:所有窗口类都必须派生自QWidget,且setMouseTracking(true)。若窗口为QMainWindow派生类,则创建一个QWidget,添加布局以把QMainWindow放置到QWidget上。使用setGeometry设置左右窗口位置,然后重载mouseMoveEvent。此外考虑,拉伸窗口时,右边的子窗口增大,还要重载resizeEvent
B1::B1(QWidget* parent) : QWidget(parent), ui(new Ui::B1)
{
    ui->setupUi(this);
    setMouseTracking(true);

    // 左窗口为QMainWindow的处理方法
    left = new QWidget(this);
    QHBoxLayout* leftLayout = new QHBoxLayout;
    My_MainWindow* leftWidget = new My_MainWindow;
    leftLayout->addWidget(leftWidget);
    left->setLayout(leftLayout);
    // 右窗口为QWidget无需处理
    right = new My_Widget(this);
    const int defaultWidth = 500; // 左窗口初始宽度
    left->setGeometry(0, 0, defaultWidth, height());
    right->setGeometry(defaultWidth, 0, width()-defaultWidth, height());
    right->setMinimumWidth(100); // 如果是osg模型要加上这句,否则拖动到最右侧删掉模型
    left->setMouseTracking(true);
    right->setMouseTracking(true);
}

void B1::resizeEvent(QResizeEvent* event)
{
    left->setGeometry(0, 0, left->width(), height());
    right->setGeometry(left->width(), 0, width() - left->width(), height());
}

void B1::mouseMoveEvent(QMouseEvent* event)
{
    if (event->pos().x() >= 10 && event->pos().x() <= width() - 10)
    {
        setCursor(Qt::SizeHorCursor);
        if (event->pos().x() >= (left->width() - 500) && event->pos().x() <= width() - (right->width() - 500))
        {
            if (event->buttons() == Qt::LeftButton)
            {
                left->setGeometry(0, 0, event->x(), height());
                right->setGeometry(left->width(), 0, width() - left->width(), height());
            }
        }
    }
    else
    {
        setCursor(Qt::ArrowCursor);
    }
}

相关文章

  • 重载resizeEvent

    简单实现 目标:改变窗口大小时,窗口中的控件布局将相应改变。如:窗口中包含两个QPushButton控件,宽度小于...

  • canvas动画

    (function(){var resizeEvent = ...

  • Element分析(工具篇)——ResizeEvent

    说明 用来监听元素的大小改变的。具体原理可以查看我的分析:奇技淫巧——通过scroll来监听resize 源码注解

  • PHP编程开发技巧:PHP中重载如何实现

    PHP编程开发技巧:PHP中重载如何实现,重载分为属性重载和方法重载,在PHP中的重载和在其它编程语言的重载不一样...

  • C++操作符重载

    重载操作符的限制 可以重载的操作符 不能重载的算符 操作符重载的语法形式 重载赋值操作符 重载+-*/运算操作符操...

  • Java重载与重写

    简言 重写和重载都是面向对象多态的一种表现,重载是编译时多态,重载是运行时多态. 重载 重载(Overloadin...

  • C++基础-(重载)

    C++基础 重载 哪些运算符可以被重载:::,.,->,*,?:不能被重载 重载操作符的标志(operator) ...

  • C++ 部分运算符重载

    可重载的运算符 不可重载的运算符和符号 重载运算符为类的成员函数 重载运算符为友元函数 重载赋值运算符 重载流插入...

  • 2019-07-11 运算符的重载

    运算符的重载 重载运算符 (“::”,“.*”,“.”,“?:”)不能被重载。 重载运算符时,不能改变其本质,如不...

  • Cocos2dx之C++基础(四)

    函数重载函数不以返回值来区分重载函数函数不以参数名来区分重载函数使用重载函数的时候不要引起二义性结构函数也可以重载...

网友评论

      本文标题:重载resizeEvent

      本文链接:https://www.haomeiwen.com/subject/ebpnnftx.html