【Qt笔记】QStackedWidget控件详解

news2024/9/24 10:29:56

目录

引言

一、基础功能

二、属性设置

2.1 属性介绍

2.2 代码示例 

2.3 代码解析

三、常用API

3.1 添加子部件

3.2 插入子部件

3.3 移除子部件

3.4 设置当前页面索引值

3.5 设置当前显示子部件

3.6 返回索引处子部件指针

3.7 返回子部件索引值

四、信号与槽

4.1 currentChanged

4.2 widgetRemoved

五、应用示例

5.1 代码 

5.2 实现效果

5.3 代码解析

结语


引言

QStackedWidget是 Qt 框架中的一个非常有用的控件,它允许你堆叠多个窗口部件(widgets),但一次只显示一个。这种机制非常适合于实现向导、多视图应用程序、选项卡界面(虽然它没有内置的选项卡头)以及表单向导等场景。通过改变当前索引,可以轻松地切换显示的窗口部件。

 

一、基础功能

QStackedWidget是Qt框架中的一个容器控件,用于在同一区域内动态地堆叠和显示不同的子部件(如窗口、对话框、页面等)。它一次只显示一个子部件,但允许开发者通过编程方式轻松地在这些子部件之间切换。

  • 页面堆叠:QStackedWidget通过堆叠的方式管理多个页面(子部件),每个页面都有一个唯一的索引值。只有当前索引对应的页面是可见的,其他页面则会被隐藏。
  • 动态切换:开发者可以通过设置当前索引或当前子部件来动态地切换显示的页面。这种切换是即时的,且可以响应各种事件或用户操作。
  • 灵活布局:QStackedWidget本身并不提供布局管理功能,但它可以与其他布局管理器(如QVBoxLayout、QHBoxLayout等)结合使用,以实现复杂的界面布局。

二、属性设置

2.1 属性介绍

虽然QStackedWidget没有像QWidget那样众多的属性需要直接设置,但它通过其API函数提供了丰富的控制手段。以下是一些与属性设置相关的要点:

  • 当前页面索引(currentIndex):这是一个只读属性,用于获取当前显示的页面的索引值。虽然不能直接设置该属性,但可以通过调用setCurrentIndex()函数来改变当前页面。
  • 当前页面(currentWidget):这同样是一个只读属性,返回当前显示的页面的指针。同样地,不能直接设置该属性,但可以通过setCurrentWidget()函数来改变当前页面。
  • 页面计数(count):这是一个只读属性,返回QStackedWidget中子部件的数量。这有助于在编程时遍历或检查子部件。

2.2 代码示例 

以下是为QStackedWidget的currentIndex、currentWidget和count属性提供代码示例的方式。需要注意的是,由于currentIndex和currentWidget是只读属性,我们不能直接“设置”它们,但可以通过调用相关函数来改变它们所代表的状态。

#include <QApplication>  
#include <QStackedWidget>  
#include <QPushButton>  
#include <QVBoxLayout>  
#include <QWidget>  
#include <QLabel>  
  
int main(int argc, char *argv[]) {  
    QApplication app(argc, argv);  
  
    // 创建主窗口  
    QWidget window;  
    QVBoxLayout *layout = new QVBoxLayout(&window);  
  
    // 创建QStackedWidget  
    QStackedWidget *stackedWidget = new QStackedWidget;  
  
    // 添加几个页面到QStackedWidget  
    QWidget *page1 = new QWidget;  
    QLabel *label1 = new QLabel("Page 1", page1);  
    QVBoxLayout *page1Layout = new QVBoxLayout(page1);  
    page1Layout->addWidget(label1);  
  
    QWidget *page2 = new QWidget;  
    QLabel *label2 = new QLabel("Page 2", page2);  
    QVBoxLayout *page2Layout = new QVBoxLayout(page2);  
    page2Layout->addWidget(label2);  
  
    QWidget *page3 = new QWidget;  
    QLabel *label3 = new QLabel("Page 3", page3);  
    QVBoxLayout *page3Layout = new QVBoxLayout(page3);  
    page3Layout->addWidget(label3);  
  
    stackedWidget->addWidget(page1);  
    stackedWidget->addWidget(page2);  
    stackedWidget->addWidget(page3);  
  
    // 将QStackedWidget添加到主窗口布局  
    layout->addWidget(stackedWidget);  
  
    // 创建按钮来切换页面  
    QPushButton *prevButton = new QPushButton("Previous");  
    QPushButton *nextButton = new QPushButton("Next");  
    QHBoxLayout *buttonLayout = new QHBoxLayout;  
    buttonLayout->addWidget(prevButton);  
    buttonLayout->addWidget(nextButton);  
    layout->addLayout(buttonLayout);  
  
    // 初始时禁用“Previous”按钮  
    prevButton->setEnabled(false);  
  
    // 连接信号与槽以切换页面  
    QObject::connect(nextButton, &QPushButton::clicked, [stackedWidget, prevButton]() {  
        int currentIndex = stackedWidget->currentIndex();  
        if (currentIndex < stackedWidget->count() - 1) {  
            stackedWidget->setCurrentIndex(currentIndex + 1);  
            prevButton->setEnabled(true);  
        }  
    });  
  
    QObject::connect(prevButton, &QPushButton::clicked, [stackedWidget]() {  
        int currentIndex = stackedWidget->currentIndex();  
        if (currentIndex > 0) {  
            stackedWidget->setCurrentIndex(currentIndex - 1);  
            if (currentIndex == 1) {  
                // 在这个简单的例子中,我们总是启用“Previous”按钮  
                // 但在更复杂的应用中,你可能需要根据实际情况来决定是否禁用它  
            }  
        }  
    });  
  
    // 示例:打印当前页面索引和页面计数  
    qDebug() << "Initial current index:" << stackedWidget->currentIndex();  
    qDebug() << "Total page count:" << stackedWidget->count();  
  
    // 示例:通过currentWidget获取当前页面并打印其标签文本(假设标签是页面的直接子部件)  
    if (QLabel *currentLabel = stackedWidget->currentWidget()->findChild<QLabel*>()) {  
        qDebug() << "Current page label text:" << currentLabel->text();  
    }  
  
    window.setWindowTitle("QStackedWidget Example");  
    window.resize(400, 300);  
    window.show();  
    return app.exec();  
}

2.3 代码解析

在这个示例中:

  • 我们创建了一个QStackedWidget并向其中添加了三个页面。
  • 每个页面都是一个包含QLabel的QWidget。
  • 我们添加了两个按钮来在页面之间切换,并根据当前页面索引启用或禁用“Previous”按钮。
  • 使用qDebug()打印了初始的当前页面索引和页面总数,展示了如何访问这些只读属性。
  • 我们还展示了如何通过currentWidget()获取当前页面,并使用findChild<QLabel*>()查找并打印当前页面上QLabel的文本(注意:这种方法假设QLabel是页面的直接子部件,且页面上只有一个QLabel)。在实际应用中,你可能需要更复杂的逻辑来定位特定的子部件。

三、常用API

QStackedWidget提供了丰富的API函数,以便开发者能够灵活地管理和控制其包含的页面。以下是一些常用的API函数及其说明:

3.1 添加子部件

addWidget(QWidget *widget, int index = -1):向QStackedWidget中添加一个子部件。如果指定了索引(index),则子部件将被插入到该索引位置;如果未指定索引(或指定为-1),则子部件将被添加到末尾。

// 创建一个主窗口  
QWidget window;  
QVBoxLayout *layout = new QVBoxLayout(&window);  
  
// 创建一个QStackedWidget  
QStackedWidget *stackedWidget = new QStackedWidget;  
  
// 创建几个页面  
QWidget *page1 = new QWidget;  
QLabel *label1 = new QLabel("Page 1", page1);  
QVBoxLayout *page1Layout = new QVBoxLayout(page1);  
page1Layout->addWidget(label1);  
  
QWidget *page2 = new QWidget;  
QLabel *label2 = new QLabel("Page 2", page2);  
QVBoxLayout *page2Layout = new QVBoxLayout(page2);  
page2Layout->addWidget(label2);  

QWidget *page3 = new QWidget;  
QLabel *label3 = new QLabel("Page 3", page3);  
QVBoxLayout *page3Layout = new QVBoxLayout(page3);  
page3Layout->addWidget(label3);  
  
// 使用addWidget添加页面到末尾  
stackedWidget->addWidget(page1);  
stackedWidget->addWidget(page2);

3.2 插入子部件

insertWidget(int index, QWidget *widget):在指定索引处插入一个子部件。如果索引超出当前范围,则子部件将被添加到末尾。

// 使用insertWidget在指定索引处插入页面  
stackedWidget->insertWidget(1, page3); // 这将page3插入到page1和page2之间  

3.3 移除子部件

removeWidget(QWidget *widget):从QStackedWidget中移除一个子部件。子部件本身不会被删除,只是从布局中移除,从而被隐藏。

// 假设现在想要移除page2  
stackedWidget->removeWidget(page2);  

3.4 设置当前页面索引值

setCurrentIndex(int index):设置当前显示的页面的索引值。如果索引值超出范围,则不会改变当前页面。

// 设置当前页面索引  
stackedWidget->setCurrentIndex(0); // 显示page1

3.5 设置当前显示子部件

setCurrentWidget(QWidget *widget):设置当前显示的子部件。如果指定的子部件已经存在于QStackedWidget中,则它将成为当前页面;如果不存在,则什么也不会发生。

3.6 返回索引处子部件指针

widget(int index):返回指定索引处的子部件的指针。如果索引超出范围,则返回nullptr。

// 获取并显示指定索引处的子部件  
QWidget *currentPage = stackedWidget->widget(0);  
if (currentPage) {  
    QLabel *currentLabel = currentPage->findChild<QLabel*>();  
    if (currentLabel) {  
        qDebug() << "Current page label text:" << currentLabel->text();  
    }  
} 

3.7 返回子部件索引值

indexOf(QWidget *widget):返回子部件在QStackedWidget中的索引值。如果子部件不存在于QStackedWidget中,则返回-1。

// 获取子部件在QStackedWidget中的索引  
int index = stackedWidget->indexOf(page3);  
qDebug() << "Index of page3:" << index; // 应该输出1,除非在添加/移除后修改了索引

四、信号与槽

QStackedWidget还提供了几个信号,以便在页面切换或页面被移除时通知开发者。这些信号可以与槽函数(即回调函数)连接,以执行特定的操作。

4.1 currentChanged

currentChanged(int index):当当前显示的页面改变时发射。参数index是新显示的页面的索引值。

// 连接currentChanged信号  
connect(stackedWidget, &QStackedWidget::currentChanged, this, [=](int index) {  
    qDebug() << "Current page changed to index:" << index;  
}); 

4.2 widgetRemoved

widgetRemoved(int index):当一个小部件(页面)从QStackedWidget中移除时发射。参数是被移除的小部件的索引值。

// 连接widgetRemoved信号  
connect(stackedWidget, &QStackedWidget::widgetRemoved, this, [=](int index) {  
    qDebug() << "Widget removed from index:" << index;  
}); 

五、应用示例

5.1 代码 

以下是一个简化的向导示例,展示了如何使用QStackedWidget来实现一个多步骤的向导界面。

#include <QApplication>  
#include <QStackedWidget>  
#include <QLabel>  
#include <QPushButton>  
#include <QVBoxLayout>  
#include <QHBoxLayout>  
  
class Wizard : public QWidget {  
    Q_OBJECT  
public:  
    Wizard(QWidget *parent = nullptr) : QWidget(parent) {  
        auto *stackedWidget = new QStackedWidget(this);  
  
        // 创建向导页面  
        QWidget *page1 = createPage("Welcome", "This is the first page of the wizard.");  
        QWidget *page2 = createPage("Name", "Enter your name:");  
        QWidget *page3 = createPage("Finish", "Thank you! You have completed the wizard.");  
  
        stackedWidget->addWidget(page1);  
        stackedWidget->addWidget(page2);  
        stackedWidget->addWidget(page3);  
  
        // 导航按钮  
        auto *backButton = new QPushButton("Back", this);  
        auto *nextButton = new QPushButton("Next", this);  
  
        // 禁用“后退”按钮在第一页  
        backButton->setEnabled(false);  
  
        // 布局  
        auto *mainLayout = new QVBoxLayout(this);  
        mainLayout->addWidget(stackedWidget);  
  
        auto *buttonLayout = new QHBoxLayout();  
        buttonLayout->addWidget(backButton);  
        buttonLayout->addWidget(nextButton);  
        mainLayout->addLayout(buttonLayout);  
  
        // 连接信号和槽  
        connect(nextButton, &QPushButton::clicked, [=]() {  
            if(nextButton->text() == "Finish")
            {
                this->close();
            }
            int currentIndex = stackedWidget->currentIndex();  
            if (currentIndex < stackedWidget->count() - 1) {  
                stackedWidget->setCurrentIndex(currentIndex + 1);  
                if (currentIndex == 1) { // 假设第二页是最后一页需要处理的  
                    // 在这里处理用户输入,如验证名称等  
                    // ...  
                }  
                backButton->setEnabled(true);  
                if (currentIndex == stackedWidget->count() - 2) {  
                    // 在最后一页设置“下一步”按钮文本
                    nextButton->setText("Finish");   
                }  
            }  
        });  
  
        connect(backButton, &QPushButton::clicked, [=]() {  
            int currentIndex = stackedWidget->currentIndex();  
            if (currentIndex > 0) {  
                stackedWidget->setCurrentIndex(currentIndex - 1);  
                backButton->setEnabled(currentIndex > 0);  
                if (currentIndex == 1) {  
                    nextButton->setText("Next");  
                    nextButton->setEnabled(true);  
                }  
            }  
        });  
  
        // 初始显示第一步  
        stackedWidget->setCurrentIndex(0);  
    }  
  
private:  
    QWidget *createPage(const QString &title, const QString &text) {  
        QWidget *page = new QWidget();  
        QLabel *label = new QLabel(text, page);  
        QVBoxLayout *layout = new QVBoxLayout(page);  
        layout->addWidget(new QLabel(title, page));  
        layout->addWidget(label);  
        return page;  
    }  
};  
  
// ... (main函数和QApplication的实例化)

5.2 实现效果

 

5.3 代码解析

在这个示例中,我们创建了一个简单的向导,它有三个页面:欢迎页、名称输入页和完成页。通过createPage辅助函数,我们简化了页面创建的过程。导航按钮根据当前页面的索引启用或禁用,并在最后一页时将“下一步”按钮的文本更改为“完成”并且在判断识别到文本更改为”Finsh“,并点击时,关闭窗口。这个示例展示了如何在页面切换时执行简单的逻辑,并管理按钮的启用/禁用状态。 

结语

QStackedWidget是Qt框架中一个非常实用的控件,它允许开发者在一个固定区域内堆叠多个子窗口或页面,并通过切换来显示不同的内容。通过使用QStackedWidget,我们可以轻松地创建多页的用户界面,如向导、选项卡等。希望本文的详细解析和示例代码能够帮助你更好地理解和使用QStackedWidget。 

 

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

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

相关文章

device靶机详解

靶机下载地址 https://www.vulnhub.com/entry/unknowndevice64-1,293/ 靶机配置 主机发现 arp-scan -l 端口扫描 nmap -sV -A -T4 192.168.229.159 nmap -sS -Pn -A -p- -n 192.168.229.159 这段代码使用nmap工具对目标主机进行了端口扫描和服务探测。 -sS&#xff1a;使用…

C++存储数据单位转换输出字符串

C封装存储数据单位转换, 方便将输入数据以指定方式输出 main.cpp #include <wtypesbase.h> #include <string> #include <vector> #include <tchar.h>#ifdef _UNICODE using _tstring std::wstring; #else using _tstring std::string; #endif// 数…

typename、非类型模板参数、模板参数的特化、模板类成员函数声明和定义分离、继承等的介绍

文章目录 前言一、typename二、非类型模板参数三、模板参数的特化1. 函数模板参数的特化2. 类模板的特化 四、模板类成员函数声明和定义分离1. 显示实例化&#xff08;不建议使用&#xff09;2. 将生命和定义写在同一个.h文件中 五、 继承总结 前言 typename、非类型模板参数、…

解析rss链接数据,来长期把某博客数据订阅到自己的网站

目的 当我们打开这个订阅链接&#xff0c;会看到我们的文章信息以xml的形式呈现到浏览器页面中&#xff0c;怎么直接在我们自己的网站中&#xff0c;将这个链接的数据转为我们熟悉的json数据&#xff0c;然后渲染到自己的网站中呢 技术栈 react hookstypescriptwebpack 核心…

【SemeDrive】【X9HP】【PTG4.3】解决Partition Flash Error及PTG4.3二级分区烧录与升级问题

前言&#xff1a;PTG4.1 之前的版本使用的都是普通 emmc 和 一级分区表&#xff0c;PTG4.3 新增了 virtio-eMMC 功能和二级分区表的设置&#xff0c;因此关于 PTG4.3 的烧录和升级有以下几个疑问和解答。 一、名词解释 virtio-eMMC&#xff1a;基于 Virtio 框架的虚拟化 EMMC…

如何在 Apache 中仅开启 TLS 1.3 / TLS1.2 ?

互联网之所以运行良好&#xff0c;是因为它可以安全地发送数据&#xff0c;这要归功于传输层安全(TLS)等技术。TLS 是安全套接字层(SSL)的新版本&#xff0c;它有助于保持网络流量的安全。本文将讨论 TLS 1.3 和 1.2&#xff0c;它们比旧版本更好、更快。 使用这些协议的一个流…

数据结构-线性表的单链式存储结构图解及C语言实现

概念 链式存储&#xff1a;结点在存储器中的位置是任意的&#xff0c;即逻辑相邻的数据元素在物理上不一定相邻 链式存储结构也称非顺序映像或链式映像 图解 链式存储结构中结点一般有两个部分组成&#xff0c;即数据域(data)和指针域&#xff0c;数据域是用于存放数据的&…

目标检测——VOC2007数据集

目标检测入门code 文件目录 下载数据集——在官网下载VOC2007数据集 下载训练数据集 TRAIN data 下载测试数据集 TEST data 解压数据集 解压——训练数据集&#xff0c;在服务器上&#xff0c;目录为VOCdevkit 部分文件目录 全部文件总目录 解压——测试数据集 &#xff08;…

Python画笔案例-061 绘制万花筒

1、绘制万花筒 通过 python 的turtle 库绘制 万花筒,如下图: 2、实现代码 绘制 万花筒,以下为实现代码: """万花筒.py本程序需要coloradd模块支持,安装方法:pip install coloradd技术支持微信scartch8,QQ:406273900""" import turtle from…

桌球计时计费系统计费方式有哪些 哪个好用 佳易王台球计时计费管理系统操作教程

一、前言 桌球计时计费系统计费方式有哪些 哪个好用 佳易王台球计时计费管理系统操作教程 1、佳易王桌球计时计费软件&#xff0c;可以多种单价计费方式&#xff0c;具体使用哪种计费方式可以根据自己的情况设置即可。 2、软件已内置数据库不需再安装&#xff0c;解压即可。 …

奇瑞汽车—经纬恒润 供应链技术共创交流日 成功举办

2024年9月12日&#xff0c;奇瑞汽车—经纬恒润技术交流日在安徽省芜湖市奇瑞总部成功举办。此次盛会标志着经纬恒润与奇瑞汽车再次携手&#xff0c;深入探索汽车智能化新技术的前沿趋势&#xff0c;共同开启面向未来的价值服务与产品新篇章。 面对全球汽车智能化浪潮与产业变革…

MovieLife 电影生活

MovieLife 电影生活 今天看到一个很有意思的项目&#xff1a;https://www.lampysecurity.com/post/the-infinite-audio-book “我有一个看似愚蠢的想法。通常&#xff0c;这类想法只是一闪而过&#xff0c;很少会付诸实践。但这次有所不同。假如你的生活是一部电影&#xff0c…

Cisco Secure Firewall Threat Defense Virtual 7.6.0 发布下载,新增功能概览

Cisco Secure Firewall Threat Defense Virtual 7.6.0 - 思科下一代防火墙虚拟设备 (FTDv) Firepower Threat Defense (FTD) Software for ESXi & KVM 请访问原文链接&#xff1a;https://sysin.org/blog/cisco-firepower-7/&#xff0c;查看最新版。原创作品&#xff0c…

为什么三星、OPPO、红米都在用它?联发科12nm级射频芯片的深度剖析

小道消息 联发科和联电在12纳米制程技术方面有潜在的合作机会… 2024年初根据相关报道,联电和英特尔宣布12纳米制程工艺合作。此外,市场传闻称联发科可能会考虑将部分订单转投给英特尔,但也有机会成为联电12纳米制程的客户。 联发科在射频产品线涵盖多种工艺和应用领域。在…

软件测试面试八股文(含文档)

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一般软件测试的面试分为三轮&#xff1a;笔试&#xff0c;HR面试&#xff0c;技术面试。 前两轮&#xff0c;根据不同企业&#xff0c;或有或无&#xff0c;但最…

建立分支提交代码

git分支 git branch 产看当前分支 git branch -a 查看所有分支 git checkout 分支名 切换分支 git checkout -b 分支名 建立分支&#xff08;仅仅是在本地建立了&#xff0c;并没有关联线上&#xff09; git push --set-upstream origin 分支名 把本地分支推到先线上 建立分支…

3、SRGAN

3、SRGAN SRGAN论文链接&#xff1a;SRGAN SRGAN&#xff08;超分辨率生成对抗网络&#xff09;是在2017年由Christian Ledig等人在论文《Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network》中提出的。该模型引入了基于GAN&#xff08;…

9.5HSV体系进行颜色分割

基本概念 inRange() 函数是 OpenCV 中用于图像处理的一个非常有用的函数&#xff0c;即从图像中提取出介于指定范围内的像素值。这个函数在图像处理中特别有用&#xff0c;比如颜色检测、背景去除等应用。它主要用于图像的阈值处理&#xff0c;但与其他阈值方法&#xff08;如…

AOT源码解析4.1-model主体解析

1 输入数据 VOS的数据集处理操作可见数据集操作&#xff0c;这里是进行数据集提取完毕后的操作。 图2&#xff1a;如图所示&#xff0c;使用datasets提取出数据之后&#xff0c;在模型训练阶段对数据做图中操作。即&#xff1a;将batch_size大小的ref_imgs、prev_imgs&#x…

【JavaEE】——线程“饿死问题” wait notify

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 引子&#xff1a; 一&#xff1a;情景引入 二&#xff1a;线程饿死问题 1&#xff1a;线程饿死 2&a…