【QT入门】 QScrollArea实际运用之滑动Widget设计

往期回顾:

【QT入门】 QListWidget各种常见用法详解之列表模式-CSDN博客

【QT入门】 QListWidget各种常见用法详解之图标模式-CSDN博客

【QT入门】 QScrollArea实际运用之导航栏设计-CSDN博客

 【QT入门】 QScrollArea实际运用之滑动Widget设计

我们通过一个实例来讲解QScrollArea的具体方法,并通过纯手写代码实现该实例。

本文承接上文导航栏设计,开始考虑右边的滑动Widget设计。

一、QScrollArea

1、简单介绍

QScrollArea是Qt中用于实现滚动区域的小部件类,它提供了一个可滚动的视图区域,用于显示超出可见区域的内容。通过将其他小部件放置在QScrollArea中,可以实现在需要时自动启用滚动条来查看内容。

2、主要特点和用法

滚动内容QScrollArea 可以容纳其他小部件作为其子部件,并在内容超出显示区域时启用滚动条,允许用户滚动查看内容。

自适应大小

QScrollArea 可以根据其子部件的大小自动调整大小,以确保内容可以正确显示,并在需要时启用滚动条。
设置滚动条策略可以通过设置 QScrollArea 的滚动条策略来指定何时显示滚动条,包括垂直滚动条、水平滚动条或两者都显示。
内边距可以设置内边距以控制内容与滚动区域边缘之间的间距。
放大缩小QScrollArea 还支持放大和缩小内容,以便用户可以调整内容的大小以适应视图区域。

二、最终效果

 由于QScrollArea能够提供了一个可滚动的视图区域,用于显示超出可见区域的内容,我们模仿迅雷去做一个界面,左边用QListWidget实现不同tab页面,右边用QScrollArea实现可以进行滚动的效果。

 三、思路

1、左边导航栏实现 

【QT入门】 QScrollArea实际运用之导航栏设计-CSDN博客

2、 右边滑动Widget设计

右边用了QScrollArea来做滑动往下的,里面是一个个widget,每个widget里面再做相应的基本界面设计。在这些widget里做了三个不同类型的,我们一个一个看:

1、完全自己手敲实现的一个widget界面
2、直接粘贴图片资源
3、先创建类用QPixmap放图片,做自适应最后放widget里
2.1、纯手敲实现 
2.1.1新建类

在当前项目新建一个类,在这个类里面实现(右键单击项目->添加->类)

2.1.2类初始化

初始化该类,添加构造函数、析构函数等

#pragma once
#include <QWidget>

class CBaseSetWidget: public QWidget
{
public:
 CBaseSetWidget(QWidget* parent = Q_NULLPTR);
 ~CBaseSetWidget();
};    

 布局设计习惯以后做这样一个界面应该不是一件很难的事情了,就是要注意把逻辑梳理出来,免得写着写着就懵了。

2.1.3布局逻辑梳理

 总共都是6个水平布局,2个竖直布局,另外就是注意下每个模块之间的间距等,这个代码简单但冗长,源代码放在这,记不住了就回来看看。

2.1.4示例代码
CBaseSetWidget::CBaseSetWidget(QWidget* parent)
    :QWidget(parent)
{
	setWindowFlags(Qt::FramelessWindowHint);
	setAttribute(Qt::WA_StyledBackground);
	this->setStyleSheet("background-color:rgb(51, 51, 51);color:rgb(200,200,200);");

	QLabel* pBasesetLabel = new QLabel(this);
	pBasesetLabel->setText(u8"基本设置");

	QCheckBox* pCheckKaijiqidong = new QCheckBox(this);
	pCheckKaijiqidong->setText(u8"开机启动");

	QCheckBox* pCheckMiandarao = new QCheckBox(this);
	pCheckMiandarao->setFixedWidth(140);
	pCheckMiandarao->setText(u8"开启免打扰模式");

	QLabel* p1 = new QLabel(this);
	p1->setText("?");

	QCheckBox* pCheckBosskey = new QCheckBox(this);
	pCheckBosskey->setFixedWidth(105);
	pCheckBosskey->setText(u8"开启老板键");

	QLineEdit* pLineEdit = new QLineEdit(this);
	pLineEdit->setFixedWidth(100);
	pLineEdit->setStyleSheet("border-style:solid;border-width:1px;border-color:rgb(79,79,79);");
	QLabel* p2 = new QLabel(this);
	p2->setText("?");

	QCheckBox* pCheckNewShowMainUI = new QCheckBox(this);
	pCheckNewShowMainUI->setText(u8"新建时显示主界面");

	QLabel* pXiazaimoshi = new QLabel(this);
	pXiazaimoshi->setText(u8"下载模式");

	QRadioButton* pQuansuxiazai = new QRadioButton(this);
	pQuansuxiazai->setText(u8"全速下载");

	QRadioButton* pXiansuxiazai = new QRadioButton(this);
	pXiansuxiazai->setText(u8"限速下载");
	pXiansuxiazai->setFixedWidth(90);

	QPushButton* pBtnModify = new QPushButton(this);
	pBtnModify->setText(u8"修改设置");
	pBtnModify->setStyleSheet("background-color:#1A1A1A;color:#5F5F5F");

	QLabel* label_cfginfo = new QLabel(this);
	label_cfginfo->setText(u8"限制时间段: 00:00-23:59 最大下载速度:不限速");

	QVBoxLayout* pMainVlay = new QVBoxLayout(this);
	pMainVlay->addWidget(pBasesetLabel);
	pMainVlay->addSpacing(20);

	QHBoxLayout* pHlay1 = new QHBoxLayout(this);
	pHlay1->addSpacing(35);

	QVBoxLayout* pVlay1 = new QVBoxLayout(this);
	pVlay1->addWidget(pCheckKaijiqidong);
	pVlay1->addSpacing(20);

	QHBoxLayout* pHlay2 = new QHBoxLayout;
	pHlay2->addWidget(pCheckMiandarao);
	pHlay2->addWidget(p1);

	pVlay1->addLayout(pHlay2);  // 添加免打扰的水平布局
	pVlay1->addSpacing(20);

	QHBoxLayout* pHlay3 = new QHBoxLayout;
	pHlay3->addWidget(pCheckBosskey);
	pHlay3->addWidget(pLineEdit);
	pHlay3->addWidget(p2);

	pVlay1->addLayout(pHlay3);
	pVlay1->addSpacing(20);

	pVlay1->addWidget(pCheckNewShowMainUI);
	pVlay1->addSpacing(20);

	pVlay1->addWidget(pXiazaimoshi);  // 下载模式
	pVlay1->addSpacing(20);

	QHBoxLayout* pHlay4 = new QHBoxLayout;  //  下载模式下面的水平布局
	pHlay4->addSpacing(30);

	QVBoxLayout* pVlay2 = new QVBoxLayout(this);

	QHBoxLayout* pHlay5 = new QHBoxLayout;
	pHlay5->addWidget(pQuansuxiazai);
	pHlay5->addWidget(p2);
	pVlay2->addLayout(pHlay5);
	pVlay2->addSpacing(20);

	// 限速下载
	QHBoxLayout* pHlay6 = new QHBoxLayout;
	pHlay6->addWidget(pXiansuxiazai);
	pHlay6->addWidget(pBtnModify);
	pHlay6->addWidget(label_cfginfo);
	pHlay6->addStretch();

	pVlay2->addLayout(pHlay6);

	pHlay4->addLayout(pVlay2);

	pVlay1->addLayout(pHlay4);
	pHlay1->addLayout(pVlay1);

	pMainVlay->addLayout(pHlay1);
	pMainVlay->setContentsMargins(20, 20, 20, 20);
}
2.2、直接资源加载 

这个很简单,把资源图片添加进来,直接new 一个Widget,设置样式就是

m_pYunpanSetWidget->setStyleSheet("background-image:url(:/QScrollArea_01/resources/YunPanSet.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
2.3、自建类加载图片 
2.3.1新建类

在当前项目新建一个类,在这个类里面实现(右键单击项目->添加->类)

2.3.2类初始化

同样的初始化该类,添加构造函数、析构函数等

#pragma once

#include <QWidget>

class GaojiSetWidget : public QWidget
{
 Q_OBJECT

public:
 GaojiSetWidget(QWidget* parent = Q_NULLPTR);
 ~GaojiSetWidget();

private:

};
2.3.3创建QPixmap对象

创建QPixmap对象添加进去并自适应,这一步更是熟悉, 回忆之前的图片查看软件。

QLabel* pLabel1 = new QLabel(this);
 pLabel1->setFixedSize(1000, 541);
 QPixmap* pixmap = new QPixmap(":/QScrollArea_01/resources/GaojiSet_1.png");
 pixmap->scaled(pLabel1->size(), Qt::KeepAspectRatio);
 pLabel1->setScaledContents(true);
 pLabel1->setPixmap(*pixmap);

 QLabel* pLabel2 = new QLabel(this);
 pLabel2->setFixedSize(1000, 685);
 pixmap = new QPixmap(":/QScrollArea_01/resources/GaojiSet_2.png");
 pixmap->scaled(pLabel2->size(), Qt::KeepAspectRatio);
 pLabel2->setScaledContents(true);
 pLabel2->setPixmap(*pixmap);

 QVBoxLayout* pVLay = new QVBoxLayout(this);
 pVLay->addWidget(pLabel1);
 pVLay->setSpacing(0);
 pVLay->addWidget(pLabel2);
 pVLay->setContentsMargins(0, 0, 0, 0);

没什么特别需要注意,看多了写多了自然就是很熟悉的了。

3、整合实现最终效果

 最后就是把所有的widget全部合起来,实现滑动效果,样式优化,点击左边的listWidget跳转到ScrollArea里相应的widget。

3.1、整合Widget到QScrollArea

整合前面三个类型的Widget界面到QScrollArea上去

 3.1.1定义指针和模板

首先在.h文件里定义每个widget的指针和一个QWidget类型的vector模板

    CBaseSetWidget* m_pBaseSetWidget;
    QWidget* m_pYunpanSetWidget;
    QWidget* m_pDownloadWidget;
    QWidget* m_pJieguanWidget;
    QWidget* m_pRenwuWidget;
    QWidget* m_pTixingWidget;
    QWidget* m_pXuanfuWidget;
    GaojiSetWidget* m_pGaojiWidget;

    vector<QWidget*> m_vecWidget;

因为上面那么多widget都是继承于QWidget,放到vector里实现全部添加滑动的效果。

3.1.2添加widget到vector

每一个widget,new出来以后,都push_back到vector里面去 。

 纯手写的
 m_pBaseSetWidget = new CBaseSetWidget;
 m_vecWidget.push_back(m_pBaseSetWidget);
直接添加资源的
m_pYunpanSetWidget = new QWidget;                         
m_pYunpanSetWidget->setStyleSheet("background-image:url(:/QScrollArea_01/resources/YunPanSet.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
 m_pYunpanSetWidget->setFixedSize(1000, 478);
 m_vecWidget.push_back(m_pYunpanSetWidget);
Qpixmap自适应的
m_pGaojiWidget = new GaojiSetWidget;
 m_vecWidget.push_back(m_pGaojiWidget);
3.1.3遍历vector

最后,我们创建一个大的widget,遍历vector,把所有的widget放到大widget里,最后放到QScrollArea里面去 

 QWidget* widget = new QWidget;

 QVBoxLayout* pVLay = new QVBoxLayout(widget);

 //将所有设置的“widget”全部添加进去
 for (auto w : m_vecWidget)
 {
  pVLay->addWidget(w);
  pVLay->addSpacing(15);
 }

 pVLay->setContentsMargins(0, 5, 0, 5);

 pScrollArea->setWidget(widget);
 3.2实现页面跳转

点击listWidget上的item,实现旁边的页面跳转.

这一段代码还是需要一定熟练度的,只能说路还很长。

3.2.1知识点分析

slotItemClicked槽函数:

当QListWidget中的项被点击时,会触发该槽函数。在该槽函数中,首先将标记signFlag设为true,然后获取被点击项的文本内容,并根据该内容确定相应的QPoint位置。最后,通过设置QScrollArea的垂直滚动条值来使被点击项对应的位置显示在可视区域内。

slotValueChanged槽函数:

当QScrollArea的垂直滚动条值发生变化时,会触发该槽函数。在该槽函数中,首先判断标记signFlag是否为false,如果是,则遍历m_vecWidget中的部件,根据部件的可见性设置相应的QListWidgetItem为选中状态或非选中状态。最后,将标记signFlag设为false。

这样实现了根据QListWidget中的项点击来控制QScrollArea的滚动位置,并根据QScrollArea的滚动位置来更新QListWidget中的项的选中状态。这种交互方式可以用于实现列表项与可滚动区域之间的联动效果。 

3.2.2示例代码
 // 通过connect函数将itemClicked信号与slotItemClicked槽函数连接起来
 connect(pListWidget, &QListWidget::itemClicked, this, &QScrollArea_01::slotItemClicked);

 // 将valueChanged信号与slotValueChanged槽函数连接起来
 connect(pScrollArea->verticalScrollBar(), &QScrollBar::valueChanged,
  this, &QScrollArea_01::slotValueChanged);
}

void QScrollArea_01::slotItemClicked(QListWidgetItem* item)
{
 signFlag = true;
 QString itemText = item->text();
 QPoint widgetPos;

 int size = pStringList.size();
 for (int i = 0; i < size; i++)
 {
  if (itemText == pStringList[i])
  {
   widgetPos = m_vecWidget[i]->pos();
  }
 }

 pScrollArea->verticalScrollBar()->setValue(widgetPos.y());
}

void QScrollArea_01::slotValueChanged(int value)
{
 if (!signFlag)
 {
  int itemSize = m_vecWidget.size();
  for (int i = 0; i < itemSize; i++)
  {
   if (!m_vecWidget[i]->visibleRegion().isEmpty())
   {
    pListWidget->item(i)->setSelected(true);
    return;
   }
   else
   {
    pListWidget->item(i)->setSelected(false);
   }
  }
 }
 signFlag = false;
}

整体思路就是这样,还是有点难度,多理解。

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

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

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值