往期回顾:
【QT入门】 QListWidget各种常见用法详解之列表模式-****博客
【QT入门】 QListWidget各种常见用法详解之图标模式-****博客
【QT入门】 QScrollArea实际运用之导航栏设计-****博客
【QT入门】 QScrollArea实际运用之滑动Widget设计
我们通过一个实例来讲解QScrollArea的具体方法,并通过纯手写代码实现该实例。
本文承接上文导航栏设计,开始考虑右边的滑动Widget设计。
一、QScrollArea
1、简单介绍
QScrollArea是Qt中用于实现滚动区域的小部件类,它提供了一个可滚动的视图区域,用于显示超出可见区域的内容。通过将其他小部件放置在QScrollArea中,可以实现在需要时自动启用滚动条来查看内容。
2、主要特点和用法
滚动内容: |
QScrollArea 可以容纳其他小部件作为其子部件,并在内容超出显示区域时启用滚动条,允许用户滚动查看内容。 |
自适应大小: |
QScrollArea 可以根据其子部件的大小自动调整大小,以确保内容可以正确显示,并在需要时启用滚动条。 |
设置滚动条策略: | 可以通过设置 QScrollArea 的滚动条策略来指定何时显示滚动条,包括垂直滚动条、水平滚动条或两者都显示。 |
内边距: | 可以设置内边距以控制内容与滚动区域边缘之间的间距。 |
放大缩小: |
QScrollArea 还支持放大和缩小内容,以便用户可以调整内容的大小以适应视图区域。 |
二、最终效果
由于QScrollArea能够提供了一个可滚动的视图区域,用于显示超出可见区域的内容,我们模仿迅雷去做一个界面,左边用QListWidget实现不同tab页面,右边用QScrollArea实现可以进行滚动的效果。
三、思路
1、左边导航栏实现
【QT入门】 QScrollArea实际运用之导航栏设计-****博客
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/);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/);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 = ();
for (int i = 0; i < size; i++)
{
if (itemText == pStringList[i])
{
widgetPos = m_vecWidget[i]->pos();
}
}
pScrollArea->verticalScrollBar()->setValue(());
}
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;
}
整体思路就是这样,还是有点难度,多理解。
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!