当前位置: 首页 > news >正文

【Qt】实现顶部导航栏自适应滑动效果

需求:

顶部导航栏有若干选项,可能很多,顶部区域不能完全展示,比如10个选项,界面一次只能展示五个,那么要求把后面的选项隐藏起来,并且,当点击第四个第五个按钮的时候,自动滑动到中间位置,后面的也滑动出来。
看下效果图
在这里插入图片描述

分析

这里面有几个点:

  • 顶部导航栏的按钮会很多,要求能够正常隐藏那些显示不了的按钮
  • 顶部导航栏的按钮宽度要自适应,也就是根据按钮中的文字宽度来调整按钮宽度
  • 点击按钮实现滑动效果,注意,靠两边的按钮不滑动(比如第一个、第二个本身就应该靠边,无法滑动)
  • 滑动效果要流畅

实现方式

#pragma once#include <QtWidgets/QWidget>
#include "ui_topnavbar.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QScrollArea>
#include <QScrollBar>
#include <QLabel>
#include <QScroller>
#include <QDebug>
#include <QList>
#include <QFontMetrics>
#include <QFont>
#include <QFile>
#include <QPropertyAnimation>class TopNavBar : public QWidget
{Q_OBJECTpublic:TopNavBar(QWidget *parent = nullptr);~TopNavBar();private:void scrollToButton(QPushButton* button);// 导航栏滑动void slotTopButtonSmoothScroll(QPushButton* button); // 导航栏平滑滑动void slotButtonClicked(bool clicked);void createText(QList<QString>& buttonText);void slotTestButtonClicked(bool clicked);void loadStyleSheet();QList<QString> buttonText;QScrollArea* _scrollArea;QList<QPushButton*> _topButtons;// QPushButton* testButton = nullptr;QLabel* iconLabel;QLabel* textLabel;
};
#include "topnavbar.h"
#include <QStyle>TopNavBar::TopNavBar(QWidget *parent): QWidget(parent)
{this->setMinimumHeight(500);this->setMinimumWidth(800);loadStyleSheet();createText(buttonText);// 创建一个滚动区域_scrollArea = new QScrollArea(this);_scrollArea->setWidgetResizable(true);// 内部控件自动填充滚动区域_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);// 关闭垂直滚动条显示_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);// 关闭水平滚动条显示_scrollArea->setFixedHeight(40);// 固定高度_scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);// 扩展策略QHBoxLayout* layoutButton = new QHBoxLayout;layoutButton->setSpacing(0);layoutButton->setContentsMargins(0, 0, 0, 0);// 创建一个容器用于放置按钮QWidget* buttonContainer = new QWidget(_scrollArea);buttonContainer->setLayout(layoutButton);// 循环创建按钮并添加到布局中for (int i = 0; i < 30; ++i) {QPushButton* pbutton = new QPushButton(buttonText[i], buttonContainer);// 通过样式文件 控制button中文字与边界的边距pbutton->setStyleSheet("background:rgb(225,225,225);margin: 0px;padding: 10px 24px;");// 宽度自适应  按钮宽度最小为128 要求内部文字上下边距为10px  左右边距为24px// 如果内部文字过长 则根据内部文字宽度 自适应调整按钮宽度// 获取按钮的字体QFont font = pbutton->font();// 创建 QFontMetrics 对象QFontMetrics metrics(font);// 测量文本的宽度int textWidth = metrics.horizontalAdvance(pbutton->text());// 打印文本宽度qDebug() << "Text width in pixels:" << textWidth;int buttonWidth = textWidth + 48 > 128 ? textWidth + 48 : 128;pbutton->setMinimumWidth(buttonWidth);QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);sizePolicy.setHorizontalStretch(0);sizePolicy.setVerticalStretch(0);pbutton->setSizePolicy(sizePolicy);// 高度扩展pbutton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);// 添加布局layoutButton->addWidget(pbutton);// 加入按钮列表_topButtons.push_back(pbutton);// 连接信号槽,当按钮被点击时,滚动到该按钮的位置connect(pbutton, &QPushButton::clicked, [this, pbutton]() {slotTopButtonSmoothScroll(pbutton);});// 当按钮被点击后 切换其样式 并设置其他未被选择的按钮的样式connect(pbutton, &QPushButton::clicked, this, &TopNavBar::slotButtonClicked);}// 将容器设置为滚动区域的子窗口_scrollArea->setWidget(buttonContainer);QLabel* testLabel = new QLabel;testLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);// 垂直布局QVBoxLayout* layout = new QVBoxLayout;layout->addWidget(_scrollArea);layout->addWidget(testLabel);this->setLayout(layout);
}
TopNavBar::~TopNavBar()
{}
// 没加动画  直接移动
void TopNavBar::scrollToButton(QPushButton* button) {// 计算滚动条应该滚动到的位置int scrollPosition = button->pos().x() - (_scrollArea->width() - button->width()) / 2;// qDebug() << "scrollPosition:" << scrollPosition;if (scrollPosition < 0){scrollPosition = 0;}QScrollBar* scrollBar = _scrollArea->horizontalScrollBar();scrollBar->setValue(scrollPosition);
}
// 加了动画 平滑滑动
void TopNavBar::slotTopButtonSmoothScroll(QPushButton* button) {int scrollPosition = button->pos().x() - (_scrollArea->width() - button->width()) / 2;QScrollBar* scrollBarH = _scrollArea->horizontalScrollBar();qDebug() << "----------------------------------" ;qDebug() << "button->pos().x():" << button->pos().x();qDebug() << "scrollArea->width():" << _scrollArea->width();qDebug() << "button->width():" << button->width();qDebug() << "scrollBarH->minimum():" << scrollBarH->minimum();qDebug() << "scrollBarH->maximum():" << scrollBarH->maximum();scrollPosition = qBound(scrollBarH->minimum(), scrollPosition, scrollBarH->maximum());QPropertyAnimation* smoothAnimation = new QPropertyAnimation(scrollBarH, "value");smoothAnimation->setDuration(300); // 设置动画持续时间smoothAnimation->setStartValue(scrollBarH->value());smoothAnimation->setEndValue(scrollPosition);smoothAnimation->start();// 启动动画
}
void TopNavBar::slotButtonClicked(bool clicked)
{QPushButton* pButton = dynamic_cast<QPushButton*>(sender());if (!pButton){return;}for (auto button : _topButtons){if (button == pButton){button->setStyleSheet("background:gray;margin: 0px;padding: 10px 24px;");}else{button->setStyleSheet("background:rgb(225,225,225);margin: 0px;padding: 10px 24px;");}}
}
void TopNavBar::createText(QList<QString>& buttonText)
{buttonText.push_back("Factory Reset Factory Reset");buttonText.push_back("Update");buttonText.push_back("Projects");buttonText.push_back("L");buttonText.push_back("AC Back");buttonText.push_back("Fan Mode");}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux TCP服务器和客户端学习
  • 多场景建模(二): SAR-Net(Scenario-Aware Ranking Network)
  • 学习记录——day43 C++ 异常处理
  • 4.人事管理系统(springbootvue项目)
  • Java 排序算法详解
  • 浅谈:CDN下真实IP的暴露
  • 阿尔泰科技案例解析-炼钢厂设备监测解决方案!
  • MySQL——视图(二)视图管理(7)删除视图
  • 正确的功能可将热晶体管风速计线性化
  • 基于SpringBoot的口腔管理平台
  • Linux平台屏幕|摄像头采集并实现RTMP推送两种技术方案探究
  • 利用发电量和气象数据分析来判断光伏仿真系统的准确性
  • 制作PPT流程图必备!掌握这些技巧轻松绘制流程图,简单又漂亮!
  • CPP/C语言中的位运算
  • Spring中FactoryBean的高级用法实战
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 10个确保微服务与容器安全的最佳实践
  • java 多线程基础, 我觉得还是有必要看看的
  • JavaScript设计模式系列一:工厂模式
  • JavaWeb(学习笔记二)
  • js继承的实现方法
  • MD5加密原理解析及OC版原理实现
  • PAT A1120
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • SAP云平台里Global Account和Sub Account的关系
  • SpiderData 2019年2月13日 DApp数据排行榜
  • Spring Boot MyBatis配置多种数据库
  • Vue2.x学习三:事件处理生命周期钩子
  • vue-router 实现分析
  • Windows Containers 大冒险: 容器网络
  • 成为一名优秀的Developer的书单
  • 分类模型——Logistics Regression
  • 基于组件的设计工作流与界面抽象
  • 前端工程化(Gulp、Webpack)-webpack
  • 前嗅ForeSpider采集配置界面介绍
  • 树莓派 - 使用须知
  • 做一名精致的JavaScripter 01:JavaScript简介
  • postgresql行列转换函数
  • #git 撤消对文件的更改
  • #LLM入门|Prompt#3.3_存储_Memory
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (力扣)循环队列的实现与详解(C语言)
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)linux 命令大全
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .NET BackgroundWorker
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET业务框架的构建
  • @Async 异步注解使用
  • @property括号内属性讲解
  • @RequestMapping用法详解
  • @WebService和@WebMethod注解的用法