【QT入门】 Qt代码创建布局之多重布局变换与布局删除技巧

news2024/11/16 10:33:32

往期回顾:

【QT入门】 Qt代码创建布局之栅格布局详解-CSDN博客

【QT入门】 Qt代码创建布局之分裂器布局详解-CSDN博客

【QT入门】 Qt代码创建布局之setLayout使用-CSDN博客

【QT入门】 Qt代码创建布局之多重布局变换与布局删除技巧

一、最终效果

我们先看最终要实现的效果

界面默认为一布局,在窗口右键单击弹出菜单栏,选择对应布局,界面就会变成对应布局类型,每次选择后窗口都会先清空原有布局。

比如这里,我单击右键,在弹出的菜单里选择了九布局,从而出现下图右边所示效果。

二、如何在窗口创建菜单

由于示例会用到菜单,所以先看一下菜单的创建

1、先在widget.h里定义菜单事件处理函数

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void  contextMenuEvent(QContextMenuEvent * event) override;

在Widget类中重写了菜单事件处理函数contextMenuEvent。当用户在窗口中右击鼠标时,会触发这个事件处理函数,可以在该函数中实现对右击菜单的自定义操作。

2、定义一个初始化菜单函数和QMenu类型的指针 

private:
    Ui::Widget *ui;
    void  initMenu();
    QMenu * m_pmenu=nullptr; 

3、重写菜单事件处理函数和创建菜单

void  Widget::contextMenuEvent(QContextMenuEvent * event)
{
     //调用exec函数在鼠标当前位置弹出m_switchMenu右键菜单。
    //通过QCursor::pos()函数获取当前鼠标的位置,确保右键菜单在鼠标位置上显示
     m_pmenu->exec(QCursor::pos());
}

 重写的contextMenuEvent函数,当用户在窗口中右击鼠标时会触发该函数。在函数中,使用m_pmenu(QMenu对象)调用exec函数,在鼠标当前位置(QCursor::pos())显示菜单。exec函数会在指定位置显示菜单,并阻塞程序直到用户选择一个菜单项或关闭菜单。

3.1QMenu与QAction类

 QMenu类用于创建菜单,而QAction类用于创建菜单里的一个个选项,最后用addAction方法把选项加入到菜单即可

void  Widget::initMenu()
{
    m_pmenu = new QMenu(this);
    QAction *pAce1 = new QAction("ace1");
    QAction *pAce2 = new QAction("ace2");
    QAction *pAce3 = new QAction("ace3");
    QAction *pAce4 = new QAction("ace4");
    QAction *pAce5 = new QAction("ace5");

    m_pmenu->addAction(pAce1);
    m_pmenu->addAction(pAce2);
    m_pmenu->addAction(pAce3);
    m_pmenu->addAction(pAce4);
    m_pmenu->addAction(pAce5);

    connect(pAce1,&QAction::triggered,[=]{
       QMessageBox::information(this,"title","ace1");
    });

}

4、设置菜单策略和调用初始化函数 

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

    //设置菜单策略
    this->setContextMenuPolicy(Qt::DefaultContextMenu);

    initMenu();
}

这里设置了窗口的菜单策略为默认菜单,即当用户在窗口中右击鼠标时,会显示默认的上下文菜单。 

4.1拓展菜单策略

实际上的参数有这几个:

enum ContextMenuPolicy {
        NoContextMenu,
        DefaultContextMenu,
        ActionsContextMenu,
        CustomContextMenu,
        PreventContextMenu
    };

NoContextMenu:表示没有上下文菜单,即不显示任何右击菜单。
DefaultContextMenu:表示默认上下文菜单,即显示系统默认的右击菜单。
ActionsContextMenu:表示动作上下文菜单,可能是指显示与操作相关的右击菜单。
CustomContextMenu:表示自定义上下文菜单,即显示开发者自定义的右击菜单。
PreventContextMenu:表示阻止上下文菜单,即禁止显示右击菜单。

三、实现多重布局与布局删除 

 1、多重布局

首先在widget.h文件里定义了几大布局类型:

enum VideoLayoutType
{
    OneVideo = 0,
    TwoVideo,
    ThreeVideo,
    FourVideo,
    FiveVideo,
    SixVideo,
    SeventVideo,
    EightVideo,
    NineVideo,
};

然后用了一个QMap来存放布局类型,由于map存的是键值对,所以另外存了一个值来判断选择的类型,在connect里链接菜单值和对应布局方式

QMap<QString,int> strTypeMap;
    strTypeMap["one"] = VideoLayoutType::OneVideo;
    strTypeMap["four"] = VideoLayoutType::FourVideo;
    strTypeMap["five"] = VideoLayoutType::FiveVideo;
    strTypeMap["six"] = VideoLayoutType::SixVideo;
    strTypeMap["nine"] = VideoLayoutType::NineVideo;

    connect(m_switchMenu,&QMenu::triggered,[=](QAction *action)
    {
        QString strText = action->text();
        VideoLayoutType type = VideoLayoutType(strTypeMap[strText]);
        switchLayout(type);
    });

最后用一个switch方法来判断链接的类型,并实现对应布局

 // 根据不同的视频布局类型创建不同的布局
        switch (type)
        {
        //创建一格布局
        case OneVideo:

        {
            //直接就是一个简单的栅格布局
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->addWidget(m_videoLabelList[0]);
            gLayout->setMargin(0);
        }
        break;

        // 创建四格布局
        case FourVideo:
        {
            //也是一个简单的栅格布局
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->setSpacing(0);
            gLayout->setMargin(0);

            //用for循环把四个布局一一加进去
            for (int i = 0; i < 4; i++)
            {
                gLayout->addWidget(m_videoLabelList[i], i / 2, i % 2);
            }
        }
        break;

        // 创建五格布局
        case FiveVideo:
        {
            //五格布局是上面三个,下面两个,分别用两个水平布局做,最后用一个垂直布局加进去
            QVBoxLayout* pVLay = new QVBoxLayout(this);
            pVLay->setSpacing(0);

            QHBoxLayout* pHTopLay = new QHBoxLayout(this);
            pHTopLay->setSpacing(0);
            for (int i = 0; i < 3; i++)
            {
                pHTopLay->addWidget(m_videoLabelList[i]);
            }

            QHBoxLayout* pHBottomLay = new QHBoxLayout(this);
            pHBottomLay->setSpacing(0);
            for (int i = 3; i < 5; i++)
            {
                pHBottomLay->addWidget(m_videoLabelList[i]);
            }

            pVLay->addLayout(pHTopLay);
            pVLay->addLayout(pHBottomLay);

        }
        break;

        // 创建六格布局
        case SixVideo:
        {
            //是一个简单的栅格布局,用for循环
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->addWidget(m_videoLabelList[0], 0, 0, 2, 2);
            gLayout->addWidget(m_videoLabelList[1], 0, 2);
            gLayout->addWidget(m_videoLabelList[2], 1, 2);
            gLayout->addWidget(m_videoLabelList[3], 2, 0);
            gLayout->addWidget(m_videoLabelList[4], 2, 1);
            gLayout->addWidget(m_videoLabelList[5], 2, 2);
            gLayout->setSpacing(0);
            gLayout->setMargin(0);
        }
        break;

        // 创建九格布局
        case NineVideo:
        {
            //是一个简单的栅格布局,用for循环
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->setSpacing(0);
            gLayout->setMargin(0);

            for (int i = 0; i < 9; i++)
            {
                gLayout->addWidget(m_videoLabelList[i], i / 3, i % 3);
            }
        }
        break;

可以看到,偶数布局很方便用格栅布局就能实现,而单数往往需要多个水平布局和垂直布局一起使用,创建布局的逻辑就不再细说,大家看代码

2、布局删除

 梳理一下顺序,最开始先初始化窗口,在初始化窗口方法里初始化菜单,然后才是看调用布局方法,而且布局方法里首先要清空布局,因为每次选择一个新的布局,都需要先清空原有布局,再重新进行布局。

if (layout)
        {
            QLayoutItem* child;
        //使用takeAt(0)逐个获取布局中的子项,并将其从布局中移除
            while ((child = layout->takeAt(0)) != 0)
            {
                //如果子项是一个窗口,则将其从父级移除,并释放内存
                if (child->widget())
                {
                    child->widget()->setParent(NULL);
                }

                delete child;
            }

        //最后删除整个布局对象,确保清空操作完成
            delete layout;
        }

四、完整示例代码

 1、Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets/QWidget>
#include <QLabel>
#include <QMenu>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

enum VideoLayoutType
{
    OneVideo = 0,
    TwoVideo,
    ThreeVideo,
    FourVideo,
    FiveVideo,
    SixVideo,
    SeventVideo,
    EightVideo,
    NineVideo,
};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    void  initMenu();
    void  initWidget();

private:
    //菜单事件
    void  contextMenuEvent(QContextMenuEvent *event);

    //切换不同布局
    void  switchLayout(VideoLayoutType type);

private:
    //保存视频区域
    QList<QLabel*> m_videoLabelList;
    QMenu * m_switchMenu;

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

 

2、Widget.cpp 

#include "widget.h"
#include "ui_widget.h"
#include <QAction>
#include <QMap>
#include <QLayoutItem>
#include <QGridLayout>

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

   // setWindowTitle("布局切换器");

    initWidget();

    this->resize(QSize(800,500));

    //设置了窗口的上下文菜单策略为Qt::DefaultContextMenu,表示使用默认的上下文菜单
    //当用户右键单击窗口时,将会显示默认的上下文菜单
    this->setContextMenuPolicy(Qt::DefaultContextMenu);
}

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

//处理右键菜单事件
void  Widget::contextMenuEvent(QContextMenuEvent *event)
{
    //调用exec函数在鼠标当前位置弹出m_switchMenu右键菜单。
    //通过QCursor::pos()函数获取当前鼠标的位置,确保右键菜单在鼠标位置上显示
    m_switchMenu->exec(QCursor::pos());
}

//初始化窗口界面
void  Widget::initWidget()
{
    initMenu();
    
    //用循环创建了9个QLabel对象,并为每个QLabel设置了不同的背景图片样式
        for (int i = 0; i < 9; i++)
        {
        //每次循环都创建一个新的QLabel对象,并将其指针保存在label变量中
            QLabel* label = new QLabel;
            
            //设置了label的样式表,包括背景图片、边框等样式
            //使用arg(QString::number(i + 1))将i的值加1后作为占位符 %1 的值,
            //从而在每次循环中加载不同的背景图片文件(例如1.png、2.png等)
            label->setStyleSheet(QString("QLabel{background-image:url(:/new/prefix1/res/%1.png); \
                border:1px solid gray; \
                background-position:center; \
                background-repeat:no-repeat; \
                }").arg(QString::number(i + 1)));
            
            //将每次循环创建的label对象添加到m_videoLabelList列表中
            m_videoLabelList.append(label);
        }

        switchLayout(VideoLayoutType::OneVideo);

}

//初始化菜单,实现右键单击弹出菜单
void  Widget::initMenu()
{
    m_switchMenu = new QMenu(this);
    //傻逼玩意儿的中文乱码问题
//    QAction *one = new QAction("one");
//    QAction *four = new QAction("four");
//    QAction *five = new QAction("five");
//    QAction *six = new QAction("six");
//    QAction *nine = new QAction("nine");

    m_switchMenu->addAction("one");
    m_switchMenu->addAction("four");
    m_switchMenu->addAction("five");
    m_switchMenu->addAction("six");
    m_switchMenu->addAction("nine");

    QMap<QString,int> strTypeMap;
    strTypeMap["one"] = VideoLayoutType::OneVideo;
    strTypeMap["four"] = VideoLayoutType::FourVideo;
    strTypeMap["five"] = VideoLayoutType::FiveVideo;
    strTypeMap["six"] = VideoLayoutType::SixVideo;
    strTypeMap["nine"] = VideoLayoutType::NineVideo;

    connect(m_switchMenu,&QMenu::triggered,[=](QAction *action)
    {
        QString strText = action->text();
        VideoLayoutType type = VideoLayoutType(strTypeMap[strText]);
        switchLayout(type);
    });

}


//函数根据不同的视频布局类型切换布局。
void  Widget::switchLayout(VideoLayoutType type)
{
    //获取当前窗口的布局,将其保存在layout变量中。
    //如果窗口有布局,那么layout将指向该布局;
    //如果窗口没有布局,layout将为nullptr
    QLayout* layout = this->layout();


    //对当前窗口的布局进行清空操作
    //这是因为,每次在用户选择新的布局界面前,都应该先进行当前布局的清空操作
    if (layout)
        {
            QLayoutItem* child;
        //使用takeAt(0)逐个获取布局中的子项,并将其从布局中移除
            while ((child = layout->takeAt(0)) != 0)
            {
                //如果子项是一个窗口,则将其从父级移除,并释放内存
                if (child->widget())
                {
                    child->widget()->setParent(NULL);
                }

                delete child;
            }

        //最后删除整个布局对象,确保清空操作完成
            delete layout;
        }

        // 根据不同的视频布局类型创建不同的布局
        switch (type)
        {
        //创建一格布局
        case OneVideo:

        {
            //直接就是一个简单的栅格布局
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->addWidget(m_videoLabelList[0]);
            gLayout->setMargin(0);
        }
        break;

        // 创建四格布局
        case FourVideo:
        {
            //也是一个简单的栅格布局
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->setSpacing(0);
            gLayout->setMargin(0);

            //用for循环把四个布局一一加进去
            for (int i = 0; i < 4; i++)
            {
                gLayout->addWidget(m_videoLabelList[i], i / 2, i % 2);
            }
        }
        break;

        // 创建五格布局
        case FiveVideo:
        {
            //五格布局是上面三个,下面两个,分别用两个水平布局做,最后用一个垂直布局加进去
            QVBoxLayout* pVLay = new QVBoxLayout(this);
            pVLay->setSpacing(0);

            QHBoxLayout* pHTopLay = new QHBoxLayout(this);
            pHTopLay->setSpacing(0);
            for (int i = 0; i < 3; i++)
            {
                pHTopLay->addWidget(m_videoLabelList[i]);
            }

            QHBoxLayout* pHBottomLay = new QHBoxLayout(this);
            pHBottomLay->setSpacing(0);
            for (int i = 3; i < 5; i++)
            {
                pHBottomLay->addWidget(m_videoLabelList[i]);
            }

            pVLay->addLayout(pHTopLay);
            pVLay->addLayout(pHBottomLay);

        }
        break;

        // 创建六格布局
        case SixVideo:
        {
            //是一个简单的栅格布局,用for循环
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->addWidget(m_videoLabelList[0], 0, 0, 2, 2);
            gLayout->addWidget(m_videoLabelList[1], 0, 2);
            gLayout->addWidget(m_videoLabelList[2], 1, 2);
            gLayout->addWidget(m_videoLabelList[3], 2, 0);
            gLayout->addWidget(m_videoLabelList[4], 2, 1);
            gLayout->addWidget(m_videoLabelList[5], 2, 2);
            gLayout->setSpacing(0);
            gLayout->setMargin(0);
        }
        break;

        // 创建九格布局
        case NineVideo:
        {
            //是一个简单的栅格布局,用for循环
            QGridLayout* gLayout = new QGridLayout(this);
            gLayout->setSpacing(0);
            gLayout->setMargin(0);

            for (int i = 0; i < 9; i++)
            {
                gLayout->addWidget(m_videoLabelList[i], i / 3, i % 3);
            }
        }
        break;

        default:
            break;
        }

}

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

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

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

相关文章

【前端学习——css篇】1.css的盒模型

https://github.com/febobo/web-interview 1.css的盒模型 html中的所有元素都是一个盒子&#xff0c;组成包括&#xff1a;内容content、内边距padding、边框border、外边距margin content&#xff0c;即实际内容&#xff0c;显示文本和图像 boreder&#xff0c;即边框&#…

Win10或Win11系统下西门子TIA博途运行时卡顿缓慢的解决办法总结

Win10或Win11系统下西门子TIA博途运行时卡顿缓慢的解决办法总结 首先,可以看下TIA PORTAL V19的安装条件: 处理器:Intel i5-8400H,2.5-4.2GHZ,4核以上+超线程技术,智能缓存; 内存:至少16GB,大型项目需要32GB 硬盘:必须SSD固态硬盘,至少50GB的可用空间 图形分辨率:1…

可拖拽的工作流优势多多,助力企业降本增效!

随着行业的进步和发展&#xff0c;利用低代码技术平台的优势特点&#xff0c;可以为企业带来降本增效、创造高价值和社会效益的目的。作为集系统开发、数据治理和数据分析于一身的一站式低代码技术平台服务商&#xff0c;流辰信息深知肩上背负的责任&#xff0c;为客户提供可拖…

一文读懂兼顾隐私、高性能和可拓展的公链Partisia Blockchain

目前&#xff0c;包括 Secret Network、Oasis Protocol 等在内的绝大多数以隐私为特性的可编程公链&#xff0c;在兼顾隐私的同时&#xff0c;在可拓展以及性能上或多或少的有所牺牲&#xff0c;即难以对诸多实际应用场景进行支撑。这归咎于链的设计以及共识机制的不合理&#…

【Java程序设计】【C00383】基于(JavaWeb)Springboot的水产养殖系统(有论文)

【C00383】基于&#xff08;JavaWeb&#xff09;Springboot的水产养殖系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c…

AI新工具(20240327) 自动生成带有精确躯干和手部动作的主播风格视频;新型AI搜索thinkany.ai;小米发布图像生成技术SDXS

✨ 1: Make-Your-Anchor 自动生成带有精确躯干和手部动作的主播风格视频 Make-Your-Anchor是一种革新性的系统&#xff0c;它允许用户仅使用一个人为期一分钟的视频片段进行训练&#xff0c;进而自动生成带有精确躯干和手部动作的主播风格视频。这样的系统特别适合于需要产生…

视频过大怎么发送到QQ微信?只需3步~

现在不仅仅是QQ&#xff0c;像我们常用的微信等软件&#xff0c;在传输视频时也都是有大小限制的。如果提示无法传输的话&#xff0c;我们可以从压缩视频来入手&#xff0c;好在现在压缩视频的方法多。可以直接借助视频压缩软件&#xff0c;或者利用视频编辑软件调整视频相关参…

牛客JZ21-调整数组顺序使奇数位于偶数前面

目录 问题描述示例具体思路思路一 代码实现 问题描述 输入一个长度为 n 整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有的奇数位于数组的前面部分&#xff0c;所有的偶数位于数组的后面部分&#xff0c;并保证奇数和奇数&#xff0c;偶数和偶数…

Vue 02 组件、Vue CLI

Vue学习 Vue 0201 组件引入概念组件的两种编写形式① 非单文件组件基本使用使用细节组件嵌套组件本质 VueComponent重要的内置关系 ② 单文件组件 02 Vue CLI介绍 & 文档安装使用步骤脚手架结构render默认配置ref 属性props配置mixin配置项插件scoped 样式案例&#xff1a;…

代码随想录——搜索插入位置(Leetcode35)

题目链接 class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;int left 0;int right len - 1;int index -1;while(left < len / 2){if(nums[left] target || target < nums[left]){index left;break;}else{left;}if(nums[ri…

python笔记进阶--面向对象(2)

目录 1.类和对象&#xff08;实例&#xff09; 1.1对象&#xff08;实例&#xff09; 1.1.1使用对象组织数据 1.1.2类中增加属性 1.2成员方法&#xff08;类&#xff09; 1.2.1类的定义和使用语法 1.2.2成员方法的使用 1.2.3self关键字的作用 1.3类和对象 2&#xff…

Redis面试题-缓存穿透,缓存击穿,缓存雪崩

1、穿透: 两边都不存在&#xff08;皇帝的新装&#xff09; &#xff08;黑名单&#xff09; &#xff08;布隆过滤器&#xff09; 解释&#xff1a;请求的数据既不在Redis中也不在数据库中&#xff0c;这时我们创建一个黑名单来存储该数据&#xff0c;下次再有类似的请求进来…

鸿蒙OS应用示例:【数字滚动计时】

实现效果&#xff1a; 代码示例&#xff1a; RollingText.ets 组件封装 RollingText.ets 组件封装 /*** 滚动文字特效*/ Component export default struct RollingText {private num:numberprivate timerId: number -1State counter: number 0aboutToAppear() {this.timerId…

MES管理系统与其他系统集成的重要作用

在现代制造业中&#xff0c;随着信息技术的飞速发展&#xff0c;各种管理系统如雨后春笋般涌现&#xff0c;它们各自拥有独特的优势&#xff0c;但唯有将它们紧密集成&#xff0c;才能发挥出最大的价值。其中&#xff0c;MES管理系统作为连接企业计划层与车间控制层的桥梁&…

Docker安装各种组件

列举镜像 docker images // 列举镜像 搜索镜像 docker search jdk 下载镜像&#xff1a; docker pull java 查看镜像&#xff1a; docker images 启动镜像&#xff1a; docker run -it --name jdk1.8 -d java:latest /bin/bash 查看容器&#xff1a; docker ps 查看…

苏州城市学院芮国强一行莅临聚合数据走访调研

3月19日&#xff0c;苏州城市学院校党委书记芮国强、校长赵志宏一行莅临聚合数据&#xff0c;就数据科技赋能行业升级展开调研。聚合数据董事长左磊接待来访。 城市学院党委理论学习中心组一行参观了聚合数据展厅&#xff0c;了解了聚合数据的发展历程、数据产品、应用案例、奖…

模拟算法

例题一 算法思路&#xff1a; 纯模拟。从前往后遍历整个字符串&#xff0c;找到问号之后&#xff0c;就⽤ a ~ z 的每⼀个字符去尝试替换即 可。 例题二 解法&#xff08;模拟 分情况讨论&#xff09;&#xff1a; 算法思路&#xff1a; 模拟 分情况讨论。 计算相邻两个…

Transformer 模型中增加一个 Token 对计算量的影响

Transformer 模型中增加一个 Token 对计算量的影响 Transformer 模型中增加一个 Token 对计算量的影响1. Transformer 模型简介2. Token 对计算量的影响3. 增加一个 Token 的计算量估算4. 应对策略5. 结论 Transformer 模型中增加一个 Token 对计算量的影响 Transformer 模型作…

从姿态估计到3D动画

在本文中&#xff0c;我们将尝试通过跟踪 2D 视频中的动作来渲染人物的 3D 动画。 在 3D 图形中制作人物动画需要大量的运动跟踪器来跟踪人物的动作&#xff0c;并且还需要时间手动制作每个肢体的动画。 我们的目标是提供一种节省时间的方法来完成同样的任务。 我们对这个问题…

【Canvas与艺术】简约式胡萝卜配色汽车速度表

【效果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>胡萝卜色汽车速度仪表盘简化版</title><style type"…