Qt实现手动切换多种布局

news2024/11/18 6:32:42

引言

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

示例

需求

通过点击程序界面上不同的布局按钮,使主工作区呈现出不同的页面布局,多个布局之间可以通过点击不同布局按钮切换。支持的最多的窗口为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_NAMESPACE

class ManulLayoutDialog : public QDialog
{
    Q_OBJECT

public:
    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.coloradmin.cn/o/1884237.html

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

相关文章

HarmonyOS Next开发学习手册——文本输入 (TextInput/TextArea)

TextInput、TextArea是输入框组件&#xff0c;通常用于响应用户的输入操作&#xff0c;比如评论区的输入、聊天框的输入、表格的输入等&#xff0c;也可以结合其它组件构建功能页面&#xff0c;例如登录注册页面。具体用法请参考 TextInput 、 TextArea 。 创建输入框 TextIn…

【一篇文章带你搞懂--拉链表!!!拉链表的原理是什么!】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;今天主要和大家分享一下拉链表的原理以及使用,希望对大家有所帮助。 大家可以关注我下方的链接更多优质文章供学习参考。 &#x1f49e;&#x1f49e;代码是你的画笔&#xff0c;创新是你…

怎样查看vsphere client 的登录日志

- 问题摘要&#xff1a; 怎样查看vsphere client 的登录日志 - 解决方案/工作方法 1.登录vsphere client > vc > Monitor > Tasks and Events > Events, 查看日志 2. 查看VC 的websso.log日志 /var/log/vmware/sso/websso.log 3. 可以把websso.log文件拿到本地电…

Java进阶学习|Day4.Java多线程,线程池

文章目录 了解多线程CPU进程(Process)线程多线程开发多线程优点 实现方式继承Thread类实现Runnable接口实现Callable接口 线程状态转换线程状态线程调度调整线程优先级线程睡眠线程等待线程让步线程加入线程唤醒 线程同步线程同步方式多线程间通信 线程池了解线程池定义常见接口…

操作系统入门 -- 磁盘管理

操作系统入门 – 磁盘管理 1.磁盘结构 1.1 磁盘 表盘有一些磁性物质组成的盘片&#xff0c;可以利用这些磁性物质存储二进制数据 1.2 磁道 一个盘片上被划分为很多圆环&#xff0c;这些圆环就是磁道 1.3 扇区 上述的圆环又被分为很多部分&#xff0c;这些部分称为扇区。…

Toshiba东芝TB6612FNG电机驱动IC:释放性能与多功能性

在嵌入式系统和机器人技术领域&#xff0c;电机控制是一个关键方面&#xff0c;对项目的性能和可靠性有着显著影响。东芝的TB6612FNG电机驱动IC作为一个稳健且多功能的解决方案&#xff0c;在驱动双直流电机方面脱颖而出&#xff0c;提供了高性能、可靠性和易用性。本文将深入探…

计算机视觉 | 基于 PointNet 网络的飞机零件 3D 点云分割

目录 一、简要介绍二、环境设置2.1 实验配置2.2 必要库安装 三、数据集解析3.1 数据集加载3.2 数据文件夹结构3.3 点云数据可视化3.4 数据获取与预处理3.5 数据集定义 四、模型组网4.1 PointNet 介绍4.2 Paddle模型组网4.3 模型概要 五、模型训练六、模型预测七、总结 Hi&#…

MySQL之高可用性和应用层优化(一)

高可用性 故障转移和故障恢复 在应用中处理故障转移 有时候让应用来处理故障转移会更加简单或者更加灵活。例如&#xff0c;如果应用遇到一个错误&#xff0c;这个错误外部观察者正常情况下是无法察觉的&#xff0c;例如关于数据库损坏的错误日志信息&#xff0c;那么应用可…

硬件开发笔记(二十三):贴片电阻的类别、封装介绍,AD21导入贴片电阻原理图封装库3D模型

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140110514 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

一文全概括,建议收藏,那些你不可错过的IC设计书籍合集(可下载)

集成电路设计工程师的角色不仅是推动技术创新的中坚力量&#xff0c;更是实现产品从概念到现实的关键桥梁。随着对高性能、低功耗芯片的需求不断增长&#xff0c;IC设计工程师的专业技能和知识深度成为了衡量其职业价值的重要标准。无论是在数字逻辑设计、功能验证、可测试性设…

【Python机器学习】模型评估与改进——分组交叉验证

分组交叉验证是非常常见的一种交叉验证策略&#xff0c;它适用于数据中的分组高度相关时。比如我们想构建一个从人脸图片中识别情感的系统&#xff0c;并且收集了100个人的照片的数据集&#xff0c;其中每个人都进行了多次拍摄&#xff0c;分别展示了不同的情感。我们的目标是构…

新开发的应用做ASO服务有必要吗

如果您开发了一款应用并希望在竞争激烈的应用市场中获得更多的曝光和下载&#xff0c;那么ASO服务通常是很有必要的。以下是几个关于ASO服务必要性的主要观点&#xff1a; 1、提高应用的可见性 ASO的最主要目标就是提高应用的排名&#xff0c;使应用在众多应用中脱颖而出让用…

Coze搭建《测测你的本命宠物》

前言 本文讲解如何从零开始&#xff0c;使用扣子平台去搭建《测测你的本命宠物》 《测测你的本命宠物》&#xff1a;测测你的本命宠物 - 扣子 AI Bot (coze.cn) 欢迎大家去体验一下&#xff01;&#xff01;&#xff01; 正文 接下来我们开始讲解制作这个bot的流程吧&#…

Perl语言入门指南

一、绪论 1.1 Perl语言概述 1.2 Perl的特色 1.3 Perl面临的问题 1.4 Perl语言的应用领域 二、Perl语言基础 2.1 Perl语言的历史发展 2.2 Perl语言的基本语法 2.3 Perl语言的数据类型 三、Perl语言控制结构 3.1 条件语句 3.2 循环结构 3.3 函数和子程序 四、Perl语…

Gavin大咖亲自授课:将大语言模型与直接偏好优化对齐

Gavin大咖亲自授课&#xff1a;将大语言模型与直接偏好优化对齐 Align LLMs with Direct Preference Optimization 直接偏好优化&#xff08; Direct Preference Optimization&#xff09;这绝对是天才性的算法。你会看到数学的巨大力量和巨大价值&#xff0c;你一定会很兴奋和…

基于X86+FPGA+AI的芯片缺陷检测方案

应用场景 随着半导体技术的发展&#xff0c;对芯片的良率要求越来越高。然而集成电路芯片制造工艺复杂&#xff0c;其制造过程中往往产生很多缺陷&#xff0c;因此缺陷检测是集成电路制造过程中的必备工艺。 客户需求 小体积&#xff0c;低功耗 2 x USB,1 x LAN Core-i平台无…

WhatsApp:连接世界的即时通讯巨头

在数字化浪潮席卷全球的今天&#xff0c;即时通讯工具已成为人们日常生活中不可或缺的一部分。其中&#xff0c;WhatsApp凭借其卓越的功能、出色的用户体验和广泛的用户基础&#xff0c;在全球通讯领域崭露头角&#xff0c;成为连接世界的即时通讯巨头。今天将带您深入了解What…

.NET项目使用Devexpress控件DiagramControl和QuikGraph类库实现最短路径算法可视化

说明&#xff1a; 使用控件&#xff1a;DevExpress V24.1.3&#xff08;链接&#xff1a;https://pan.baidu.com/s/1FosVrpyE7q_XvwhZK7ad3w?pwdtw64提取码&#xff1a;tw64&#xff09;项目地址&#xff1a;https://github.com/VinciYan/Diagram_NET.git可以帮助学习和理解数…

【区块链+基础设施】珠三角征信链 | FISCO BCOS应用案例

“珠三角征信链”是中国人民银行广州分行、中国人民银行深圳市中心支行按照中国人民银行总行工作部署&#xff0c;积 极贯彻珠三角一体化发展、粤港澳大湾区建设等国家战略而建设的跨区域征信一体化数据中心枢纽&#xff0c;以 FISCO BCOS 为底链构建应用平台&#xff0c;并由微…

跨越界限,巴比达带你访问远程桌面【内网穿透技术分享】

在远程工作的时代&#xff0c;远程桌面访问成为了许多职场人士的日常。Windows系统默认的远程桌面服务监听在3389端口&#xff0c;但对于内网环境下的机器来说&#xff0c;直接从外部访问这个端口常常面临重重阻碍。不过&#xff0c;有了巴比达内网穿透&#xff0c;这一切都将不…