Qt实现手动切换多种布局

引言

之前写了一个手动切换多个布局的程序,下面来记录一下。
程序运行效果如下:
在这里插入图片描述

示例

需求

通过点击程序界面上不同的布局按钮,使主工作区呈现出不同的页面布局,多个布局之间可以通过点击不同布局按钮切换。支持的最多的窗口为9个。不同布局下窗口数随之变化。

开发环境

使用的QtCreator12.0.2,基于Qt5.15.2库开发。

代码实现

创建基于QApplication的应用程序。
下面是实现代码:
main.cpp

#include "manullayoutdialog.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);ManulLayoutDialog w;w.show();ObjectPooling*m_pool = ObjectPooling::getInstance(9);return a.exec();
}

ObjectPooling.h

#ifndef OBJECTPOOLING_H
#define OBJECTPOOLING_H#include <QObject>
#include <QWidget>
#include <QVector>class ObjectPooling:public QObject
{Q_OBJECT
private:ObjectPooling(qint32 num);ObjectPooling(const ObjectPooling &) = delete;ObjectPooling& operator=(const ObjectPooling&)=delete;
public:static ObjectPooling *getInstance(qint32 num);~ObjectPooling();QWidget* takeOut();void putIn(QWidget *pWidget);int getSize()const;
private:QVector<QWidget*> m_vecWidget;
};#endif // OBJECTPOOLING_H

ObjectPooling.cpp

#include "objectpooling.h"
#include <qDebug>ObjectPooling::ObjectPooling(qint32 num):QObject() {for(int i = 0; i < num;++i){QWidget *pWidget = new QWidget;if(pWidget){pWidget->setStyleSheet("background-color:back;");m_vecWidget.push_back(pWidget);}}
}ObjectPooling *ObjectPooling::getInstance(qint32 num)
{static ObjectPooling instance(num);return &instance;
}ObjectPooling::~ObjectPooling()
{if(m_vecWidget.size()<1)return;for(auto it = m_vecWidget.begin();it != m_vecWidget.end();++it){if(*it){delete *it;(*it) = nullptr;}}m_vecWidget.clear();
}QWidget *ObjectPooling::takeOut()
{if(m_vecWidget.size()){QWidget*pWidget = m_vecWidget.back();
//        qDebug()<<"takeOut-befor : "<<m_vecWidget.size();m_vecWidget.pop_back();
//       qDebug()<<"takeOut-back : "<<m_vecWidget.size();return pWidget;}qDebug()<<"对象池没有对象了!!";return nullptr;
}void ObjectPooling::putIn(QWidget *pWidget)
{m_vecWidget.push_back(pWidget);
}int ObjectPooling::getSize() const
{return m_vecWidget.size();
}

ManulLayoutDialog.h

#ifndef MANULLAYOUTDIALOG_H
#define MANULLAYOUTDIALOG_H#include <QDialog>
#include "objectpooling.h"QT_BEGIN_NAMESPACE
namespace Ui {
class ManulLayoutDialog;
}
QT_END_NAMESPACEclass ManulLayoutDialog : public QDialog
{Q_OBJECTpublic:ManulLayoutDialog(QWidget *parent = nullptr);~ManulLayoutDialog();
private:void initLayout();void clearLastLayout(int n);//n——新的布局中窗口的总数void threeColumnLayout(int r,int c);//r——行数,c——列数
private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();void on_pushButton_3_clicked();void on_pushButton_4_clicked();void on_pushButton_5_clicked();private:Ui::ManulLayoutDialog *ui;qint32 m_n;//布局中窗口的总个数QVector<QWidget*> m_vecWidget;//保存布局中的窗口ObjectPooling* m_pool;
};
#endif // MANULLAYOUTDIALOG_H

ManulLayoutDialog.cpp

#include "manullayoutdialog.h"
#include "ui_manullayoutdialog.h"
#include <QDebug>ManulLayoutDialog::ManulLayoutDialog(QWidget *parent): QDialog(parent), ui(new Ui::ManulLayoutDialog)
{ui->setupUi(this);initLayout();
}ManulLayoutDialog::~ManulLayoutDialog()
{for(QWidget *pWidget:m_vecWidget){pWidget->setParent(nullptr);//不设置被回收的窗口父对象为空,会被再次释放ObjectPooling::getInstance(9)->putIn(pWidget);}m_vecWidget.clear();delete ui;//若被回收的窗口没有设置父对象为空,这里会析构该窗口,回收到对象池后会再次析构
}void ManulLayoutDialog::initLayout()
{QHBoxLayout *pHLayout = new QHBoxLayout(ui->widget);pHLayout->setContentsMargins(0,0,0,0);QWidget *pWidget = ObjectPooling::getInstance(9)->takeOut();pHLayout->addWidget(pWidget);m_n = 1;m_vecWidget.push_back(pWidget);m_pool = ObjectPooling::getInstance(9);
}void ManulLayoutDialog::clearLastLayout(int n)
{QLayout *pLayout = ui->widget->layout();
//    qDebug()<<"移除前的窗口数m_vecWidget: "<<m_vecWidget.size();if(m_n>n){for(int i =0; i <m_n -n;++i){//趟数//移除窗口中的控件,回收到对象池QWidget *pWidget = m_vecWidget.back();if(pLayout && pWidget){qDebug()<<"准备移除窗口===";pLayout->removeWidget(pWidget);pWidget->setParent(nullptr);m_vecWidget.pop_back();}// if(pLayout){qDebug()<<"布局不为空 ";}// if(pWidget){qDebug()<<"窗口不为空 ";}// QWidget *fWidget = pWidget->parentWidget();ObjectPooling::getInstance(9)->putIn(pWidget);// qDebug()<<"对象池窗口数m_vecWidget: "<<ObjectPooling::getInstance(9)->getSize();// qDebug()<<"移除后的窗口数m_vecWidget: "<<m_vecWidget.size();}}else if(m_n <n){//为了防止二次重设父对象,先将上一次的父对象清空for(auto it = m_vecWidget.begin();it != m_vecWidget.end();++it){if(*it){(*it)->setParent(nullptr);}}for(int i = 0; i < n-m_n;++i){m_vecWidget.push_back(ObjectPooling::getInstance(9)->takeOut());}}//删除窗口原本的布局delete pLayout;//    ui->widget->setLayout(nullptr);
}void ManulLayoutDialog::threeColumnLayout(int r, int c)
{int total = r*c;if(m_n == total){return ;}clearLastLayout(total);QGridLayout *pGridLayout = new QGridLayout(ui->widget);pGridLayout->setContentsMargins(0,0,0,0);for(int i = 0; i < r;++i){for(int j = 0; j < c; ++j){pGridLayout->addWidget(m_vecWidget[i+j+2*i],i,j);//找下标对应的位置与元素之间的关系}}m_n = total;
}void ManulLayoutDialog::on_pushButton_clicked()
{if(m_n == 1){return ;}else{clearLastLayout(1);}QHBoxLayout *pHLayout = new QHBoxLayout(ui->widget);pHLayout->setContentsMargins(0,0,0,0);// qDebug()<<"布局1中的窗口数m_vecWidget: "<<m_vecWidget.size();pHLayout->addWidget(m_vecWidget.back());m_n = 1;
}void ManulLayoutDialog::on_pushButton_2_clicked()
{if(m_n == 2){return ;}else if(m_n > 2){clearLastLayout(2);QHBoxLayout *pLayout = new QHBoxLayout(ui->widget);pLayout->setContentsMargins(0,0,0,0);for(auto it = m_vecWidget.begin();it != m_vecWidget.end();++it){pLayout->addWidget(*it);}}else{QLayout *pLayout = ui->widget->layout();QWidget *pWidget = ObjectPooling::getInstance(9)->takeOut();pLayout->addWidget(pWidget);m_vecWidget.push_back(pWidget);}m_n = 2;// qDebug()<<"布局2中的窗口数m_vecWidget: "<<m_vecWidget.size();
}void ManulLayoutDialog::on_pushButton_3_clicked()
{if(m_n == 4){return ;}clearLastLayout(4);//只能先清理之前的布局,不能与下面的新布局互换位置QGridLayout *pGridLayout = new QGridLayout(ui->widget);pGridLayout->setContentsMargins(0,0,0,0);for(int i = 0; i < 2;++i){for(int j = 0; j < 2; ++j){pGridLayout->addWidget(m_vecWidget[i+j+i],i,j);//找下标对应的位置与元素之间的关系}}m_n = 4;
}void ManulLayoutDialog::on_pushButton_4_clicked()
{threeColumnLayout(2,3);
}void ManulLayoutDialog::on_pushButton_5_clicked()
{threeColumnLayout(3,3);
}

运行结果

选一种的2行6列布局下的效果的截图。具体的运行效果和文章开始的效果一样。
在这里插入图片描述

程序分析

项目中先创建了一个单例模式下的对象池,负责布局中总窗口的创建、回收,取出、以及存入。同时创建了一个手动布局类ManulLayoutDialog,在该类中实现了在界面上点击不同布局按钮的响应,ObjectPooling类作为手动布局类ManulLayoutDialog的成员函数,两个类之间是一种关联的关系。采用队列存放布局中的窗口,当要切换的布局中的窗口数大于当前的窗口布局中的窗口数,则先清除之前的窗口布局,将布局中的窗口回收到窗口数组中,同时向对象池中取出相差数量的窗口,放入窗口数组,创建新的布局,将窗口数组中的窗口加入新布局;当要切换的布局中的窗口数小于当前的窗口布局中的窗口数,则先从布局中移除相差数量的窗口,将移除的窗口从窗口数组中去除,删除窗口原来的布局,同时将移除的窗口存入对象池中,创建新的布局,将窗口数组中的窗口加入到新的布局。

注意

示例中有两个需要注意的点:
1.对象池中窗口的释放。 可看ManulLayoutDialog的析构函数。
2.原本布局中窗口的回收。 可看clearLastLayout函数。
上面的两点在代码的注释中有写,是为重点注意项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/39046.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用 AppML

如何使用 AppML AppML(Application Markup Language)是一种轻量级的标记语言,旨在简化Web应用的创建和部署过程。它允许开发者通过XML或JSON格式的配置文件来定义应用的结构和行为,从而实现快速开发和灵活扩展。AppML特别适用于构建数据驱动的企业级应用,它可以与各种后端…

pytorch跑手写体实验

目录 1、环境条件 2、代码实现 3、总结 1、环境条件 pycharm编译器pytorch依赖matplotlib依赖numpy依赖等等 2、代码实现 import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms import matpl…

burpsuite 设置监听窗口 火狐利用插件快速切换代理状态

一、修改burpsuite监听端口 1、首先打开burpsuite&#xff0c;点击Proxy下的Options选项&#xff1a; 2、可以看到默认的监听端口为8080&#xff0c;首先选中我们想要修改的监听&#xff0c;点击Edit进行编辑 3、将端口改为9876&#xff0c;并保存 4、可以看到监听端口修改成功…

typescript学习回顾(五)

今天来分享一下ts的泛型&#xff0c;最后来做一个练习 泛型 有时候&#xff0c;我们在书写某些函数的时候&#xff0c;会丢失一些类型信息&#xff0c;比如我下面有一个例子&#xff0c;我想提取一个数组的某个索引之前的所有数据 function getArraySomeData(newArr, n:numb…

JVM原理(十):JVM虚拟机调优分析与实战

1. 大内存硬件上的程序部署策略 这是笔者很久之前处理过的一个案例&#xff0c;但今天仍然具有代表性。一个15万PV/日左右的在线文档类型网站最近更换了硬件系统&#xff0c;服务器的硬件为四路志强处理器、16GB物理内存&#xff0c;操作系统为64位CentOS5.4&#xff0c;Resin…

js数组方法归纳——concat、join、reverse

1、concat( ) 用途&#xff1a;可以连接两个或多个数组&#xff0c;并将新的数组返回该方法不会对原数组产生影响 var arr ["孙悟空","猪八戒","沙和尚"];var arr2 ["白骨精","玉兔精","蜘蛛精"];var arr3 [&…

Vue Router的深度解析

引言 在现代Web应用开发中&#xff0c;客户端路由已成为实现流畅用户体验的关键技术。与传统的服务器端路由不同&#xff0c;客户端路由通过JavaScript在浏览器中控制页面内容的更新&#xff0c;避免了页面的全量刷新。Vue Router作为Vue.js官方的路由解决方案&#xff0c;以其…

阿里云centos 取消硬盘挂载并重建数据盘信息再次挂载

一、取消挂载 umount [挂载点或设备] 如果要取消挂载/dev/sdb1分区&#xff0c;可以使用以下命令&#xff1a; umount /dev/sdb1 如果要取消挂载在/mnt/mydisk的挂载点&#xff0c;可以使用以下命令&#xff1a; umount /mnt/mydisk 如果设备正忙&#xff0c;无法立即取消…

【Spring Boot】简单了解spring boot支持的三种服务器

Tomcat 概述&#xff1a;Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta EE 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。它作为 Java Servlet、JSP、JavaServer Pages Expression Languag…

系统安全及应用(命令)

目录 一、账号安全控制 1.1 系统账号清理 1.2 密码安全控制 1.3 历史记录控制 1.4 终端自动注销 二、系统引导和登陆控制 2.1 限制su命令用户 2.2 PAM安全认证 示例一&#xff1a;通过pam 模块来防止暴力破解ssh 2.3 sudo机制提升权限 2.3.1 sudo命令&#xff08;ro…

Java的日期类常用方法

Java_Date 第一代日期类 获取当前时间 Date date new Date(); System.out.printf("当前时间" date); 格式化时间信息 SimpleDateFormat simpleDateFormat new SimpleDateFormat("yyyy-mm-dd hh:mm:ss E); System.out.printf("格式化后时间" si…

【windows|012】光猫、路由器、交换机详解

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 ​ &#x1f3c5;阿里云ACE认证高级工程师 ​ &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社…

windows USB 驱动开发-URB结构

通用串行总线 (USB) 客户端驱动程序无法直接与其设备通信。 相反&#xff0c;客户端驱动程序会创建请求并将其提交到 USB 驱动程序堆栈进行处理。 在每个请求中&#xff0c;客户端驱动程序提供一个可变长度的数据结构&#xff0c;称为 USB 请求块 (URB) &#xff0c;URB 结构描…

ctfshow-web入门-命令执行(web75-web77)

目录 1、web75 2、web76 3、web77 1、web75 使用 glob 协议绕过 open_basedir&#xff0c;读取根目录下的文件&#xff0c;payload&#xff1a; c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). ); } ex…

读书笔记-Java并发编程的艺术-第3章(Java内存模型)-第9节(Java内存模型综述)

3.9 Java内存模型综述 前面对Java内存模型的基础知识和内存模型的具体实现进行了说明。下面对Java内存模型的相关知识做一个总结。 3.9.1 处理器的内存模型 顺序一致性内存模型是一个理论参考模型&#xff0c;JMM和处理器内存模型在设计时通常会以顺序一致性内存模型为参照。…

ORB-SLAM2 安装编译运行(非 ROS)

安装编译 必备安装工具 主要包括 cmake 、 git 、 gcc 、 g gcc 的全称是 GNU Compiler Collection&#xff0c;它是由 GNU 推出的一款功能强大的、性能优越的 多平台编译器&#xff0c;是一个能够编译多种语言的编译器。最开始 gcc 是作为 C 语言的编译器&#xff08;GNU …

如何将等保2.0的要求融入日常安全运维实践中?

等保2.0的基本要求 等保2.0是中国网络安全领域的基本国策和基本制度&#xff0c;它要求网络运营商按照网络安全等级保护制度的要求&#xff0c;履行相关的安全保护义务。等保2.0的实施得到了《中华人民共和国网络安全法》等法律法规的支持&#xff0c;要求相关行业和单位必须按…

C#/WPF 自制白板工具

随着电子屏幕技术的发展&#xff0c;普通的黑板已不再适用现在的教学和演示环境&#xff0c;电子白板应运而生。本篇使用WPF开发了一个电子白板工具&#xff0c;功能丰富&#xff0c;非常使用日常免费使用&#xff0c;或者进行再次开发。 示例代码如下&#xff1a; Stack<St…

拓扑排序[讲课留档]

拓扑排序 拓扑排序要解决的问题是给一个有向无环图的所有节点排序。 即在 A O E AOE AOE网中找关键路径。 前置芝士&#xff01; 有向图&#xff1a;有向图中的每一个边都是有向边&#xff0c;即其中的每一个元素都是有序二元组。在一条有向边 ( u , v ) (u,v) (u,v)中&…

JavaScript 动态网页实例 —— 广告效果

广告是现代网页设计中不可或缺的内容。广告可以有很多种形式,但最终目的都是要吸引观众的注意力。尽管广告少不了画面、音效和广告语等效果,但其实现主要还是应用JavaScript 代码,只要很好掌握了JavaScript程序设计,剩下的就是创意和美工了。本章介绍几种广告效果,包括对联…