用qt做网易云音乐--轮播图实现(2)

在这里插入图片描述
窗体设计大概是这样
在这里插入图片描述
前面我们写到这里,接下来继续

这里的要点,每张图片的位置不同,每张图片的大小不同,没张图片显示的层级不同(就是图片重叠的情况下优先展示的)我们先看这几点,我这里把每张图片的这些特点都写进了list集合,这里详细介绍下

QList<int> m_ZValueList;    //每张图片优先级的list,设置那张图片在上那张在下,如同raise()和lower()效果
QList<qreal> m_PixmapScaleList; //每张图片的缩放比例list
QList<QPointF> m_pointList; //每张图片的点
//P1-P10,为10个将图片x轴距离原点的位置
#define P0 (qreal)0.00
#define P1 (qreal)0.15
#define P2 (qreal)0.44
#define P3 (qreal)0.15
#define P4 (qreal)0.15
#define P5 (qreal)0.15
#define P6 P1
#define P7 P1
#define P8 P1
#define P9 P1
		QList<qreal> pointList;
        pointList<< P0<< P1 << P2<< P3 << P4 << P5 << P6 << P7 << P8 << P9; //P1-P10的list
        m_ZValueList << 1 << 2 << 1  << 0  << 0  << 0  << 0  << 0  << 0  << 0;
        m_PixmapScaleList << 0.8<< 1 << 0.8 << 0 << 0 << 0 << 0 << 0 << 0<<0;
        QLineF MidLine(QPointF(0,0),QPointF(ui->bannerGraphicsView->width(),0));
        //GraphicsView的x轴长度,用他和P1-P10来确定每张图片的位置
        for(int i = 0;i < 10;i++)
        {
            QPointF point = MidLine.pointAt(pointList[i]);
            if(i != 1)
            {
               point.setY(ui->bannerGraphicsView->height()/10);
            }
            m_pointList.append(point);
        }
          //放入到对应位置

然后位置就定好了,我们初始化图片项,我这里把项也放到一个list集合里,方便以后遍历

{
    for (int i = 0; i < 10; i++)
    {
        QString pixPath = QString(":/images/homeTab/recommend/homeBanner/banner%1.png").arg(i);
        QPixmap pix = QPixmap(pixPath);
        pix = pix.scaled(ui->bannerGraphicsView->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
        //这句我也不知道有啥用,我试了去掉也没什么变化,可能图片的大小刚刚好,如果图片大小不合适的话就会出问题,还是加上合适
        itemList.append(new BannerItem(pix));
        itemList[i]->setScale(m_PixmapScaleList[i]);
        itemList[i]->setIndex(i);
        itemList[i]->setOffset(QPointF(0,0));
    }
for(int i = 0; i<10; i++)
{
    m_bannerScene->addItem(itemList[i]);//添加图元
    itemList[i]->setTransformationMode(Qt::SmoothTransformation);//设置缩放模式
    itemList[i]->setPos(m_pointList[i]);//设置位置
    itemList[i]->setZValue(m_ZValueList[i]);//设置显示优先级
}

写到这里的时候,运行起来,每张图片都已经在正确的位置了,只是还不会动,接下来我们让他动起来,这里索引有些多,小伙伴们仔细看,别搞混了

这里定义每个项的动画,因为每个项的点不同,不能使用一个动画,还是使用list集合,然后qtimeline表示动画时间和循环次数,我这里3毫秒,循环1次
给每个动画绑定项

m_itemAnimation = QVector<QGraphicsItemAnimation *>(10);
    m_timeline = new QTimeLine(300); //动画在多长时间完成,默认为1000,就是1秒
    m_timeline->setLoopCount(1);//设置1次
    for (int i = 0; i < 10; i++)
    {
        m_itemAnimation[i] = new QGraphicsItemAnimation();
        m_itemAnimation[i]->setItem(itemList[i]);
        m_itemAnimation[i]->setTimeLine(m_timeline);
    }

接下来使用QTimer 设置一个间隔setInterval()
因为我们的动画只让他动一次,过多长时间又动,需要这个计时器

计时器我就不写了,调用start函数开始计时,到间隔后发送timeout()信号,用一个槽函数接受这个信号就可以了

我定义了三个成员变量

int m_currentItemIndex;  //当前中心项索引
int m_firstItemIndex; //当前首项索引
int m_lastItemIndex; //当前尾项索引

这里时间到了,我们要整体向前推,就用这三个成员变量

`

``cpp
	m_lastItemIndex = m_firstItemIndex;
    m_firstItemIndex = m_currentItemIndex;
    m_currentItemIndex = indexMap(m_currentItemIndex+1);
    bannerRun();

这是动画函数,从第一个项向后重新定义大小,使用animation动画的setPosAt函数设置每项最终点,就完成了,这里如果到了0索引,再-1会变成
-1,如果到了9索引,再加会变成10索引,所以定义了一个索引映射函数indexMap(),保证每个索引是正确的

int CircularBannerWidget::indexMap(int index)
{
    if(index == 10)
    {
        index = 0;
    }
    if(index == -1)
    {
       index = 9;
    }
    return index;
}
void CircularBannerWidget::bannerRun()
{
    m_timeline->stop();
    int index = m_firstItemIndex;
    for (int i = 0; i<10; i++,index++)
    {
    index = indexMap(index);
    itemList[index]->setTransformationMode(Qt::SmoothTransformation);//设置缩放模式
    itemList[index]->setZValue(m_ZValueList[i]);//设置显示优先级
    itemList[index]->setScale(m_PixmapScaleList[i]);
    //itemList[index]->setPos(m_pointList[i]);
    m_itemAnimation[index]->setPosAt(0.6,m_pointList[i]);
    }
    m_timeline->start();
    m_timer->start(); //重新从0计时
    m_buttonGroup->button(m_currentItemIndex)->setChecked(true);

}

这些大体的功能就完成了,接下来就是些小细节,我就不讲了,直接上代码,大家看看就懂了

头文件

#include <QWidget>
#include <QButtonGroup>
#include <QGraphicsScene>
#include <banneritem.h>
#include <QGraphicsItemAnimation>
#include <QVector>
#include <QTimeLine>

//P1-P10,为10个将图片x轴距离原点的位置
#define P0 (qreal)0.00
#define P1 (qreal)0.15
#define P2 (qreal)0.44
#define P3 (qreal)0.15
#define P4 (qreal)0.15
#define P5 (qreal)0.15
#define P6 P1
#define P7 P1
#define P8 P1
#define P9 P1



namespace Ui {
class CircularBannerWidget;
}

class CircularBannerWidget : public QWidget
{
    Q_OBJECT

public:
    explicit CircularBannerWidget(QWidget *parent = 0);
    ~CircularBannerWidget();
    void initButtonGroup();     //初始化按钮组
    void initDisplayPositionList(); //初始化位置,优先级,缩放比例的List
    void initBanner();  //初始化轮播图
    void initTimer();   //初始化计时器
    void initSignalConnect();   //连接信号
    void setPixmapList();
    void addBannerItem();
    void initAnimationAndTimeline();
    void bannerRun();
    int indexMap(int index);  //索引映射,当index到最大或到最小转成正确的

private:
    Ui::CircularBannerWidget *ui;
    QButtonGroup *m_buttonGroup; //翻页按钮组
    QList<int> m_ZValueList;    //每张图片优先级的list,设置那张图片在上那张在下,如同raise()和lower()效果
    QList<qreal> m_PixmapScaleList; //每张图片的缩放比例list
    QGraphicsScene *m_bannerScene;  //graphicsScene指针对象
    //QList<QPixmap> m_PixmapList;
    QList<BannerItem *> itemList;   //每个轮播图项list
    QTimer *m_timer;   //计时器用来设置定时动画
    QVector<QGraphicsItemAnimation *> m_itemAnimation;  //项动画向量
    QTimeLine *m_timeline;  //timeline动画计时
    int m_currentItemIndex;  //当前中心项索引
    int m_firstItemIndex; //当前首项索引
    int m_lastItemIndex; //当前尾项索引
    QList<QPointF> m_pointList; //每张图片的点



signals:
    void ItemLink(int index);


private slots:
    void m_timer_timeout();
    void itemclick(int pageIndex);
    void buttonEnterd(int index);

    void on_lButton_clicked();
    void on_rButton_clicked();
};

源文件

#include "circularbannerwidget.h"
#include "ui_circularbannerwidget.h"
#include <QDebug>
#include <QTimer>
#include <banneritem.h>


CircularBannerWidget::CircularBannerWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::CircularBannerWidget)
{
    ui->setupUi(this);
    this->setAttribute(Qt::WA_StyledBackground);
    initButtonGroup();
    initDisplayPositionList();
    setPixmapList();
    initBanner();
    initTimer();
    initAnimationAndTimeline();
    initSignalConnect();
    m_timer->start();
    this->setStyleSheet("background:transparent");
    this->setStyleSheet("QPushButton#lButton{image:url(:/images/homeTab/recommend/homeBanner/后退.png);border-radius:10px;background-color:rgb(59,70,68,100);}"
                        "QPushButton#rButton{image:url(:/images/homeTab/recommend/homeBanner/前进.png);border-radius:10px;background-color:rgb(59,70,68,100);}"
                        "QPushButton:hover#lButton,:hover#rButton{background-color:rgb(213,43,43);}");


}

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

void CircularBannerWidget::initButtonGroup()
{
    m_buttonGroup = new QButtonGroup(this);
    m_buttonGroup->addButton(ui->page0Button,0);
    m_buttonGroup->addButton(ui->page1Button,1);
    m_buttonGroup->addButton(ui->page2Button,2);
    m_buttonGroup->addButton(ui->page3Button,3);
    m_buttonGroup->addButton(ui->page4Button,4);
    m_buttonGroup->addButton(ui->page5Button,5);
    m_buttonGroup->addButton(ui->page6Button,6);
    m_buttonGroup->addButton(ui->page7Button,7);
    m_buttonGroup->addButton(ui->page8Button,8);
    m_buttonGroup->addButton(ui->page9Button,9);
    m_buttonGroup->setExclusive(true);
    m_buttonGroup->button(1)->setChecked(true);
    for (int i = 0; i<10; i++) {
        qobject_cast<PageButton*>(m_buttonGroup->button(i))->setPage(i);
    }
}

void CircularBannerWidget::initDisplayPositionList()
{
        QList<qreal> pointList;
        pointList<< P0<< P1 << P2<< P3 << P4 << P5 << P6 << P7 << P8 << P9; //P1-P10的list
        m_ZValueList << 1 << 2 << 1  << 0  << 0  << 0  << 0  << 0  << 0  << 0;
        m_PixmapScaleList << 0.8<< 1 << 0.8 << 0 << 0 << 0 << 0 << 0 << 0<<0;
        QLineF MidLine(QPointF(0,0),QPointF(ui->bannerGraphicsView->width(),0));
        //GraphicsView的x轴长度,用他和P1-P10来确定每张图片的位置
        for(int i = 0;i < 10;i++)
        {
            QPointF point = MidLine.pointAt(pointList[i]);
            if(i != 1)
            {
               point.setY(ui->bannerGraphicsView->height()/10);
            }
            m_pointList.append(point);
        }
          //放入到对应位置
}

void CircularBannerWidget::initBanner()
{
    ui->bannerGraphicsView->setStyleSheet("background: transparent; padding: 0px; border: 0px;");
    m_bannerScene = new QGraphicsScene(this);
    ui->bannerGraphicsView->setScene(m_bannerScene);
    ui->bannerGraphicsView->setSceneRect(0,0,ui->bannerGraphicsView->width(),ui->bannerGraphicsView->height());
    addBannerItem();
    m_currentItemIndex = 1;
    m_firstItemIndex = 0;
    m_lastItemIndex = 9;
}


void CircularBannerWidget::initTimer()
{
    m_timer = new QTimer(this);
    m_timer->setInterval(5000);
}

void CircularBannerWidget::initSignalConnect()
{
    connect(m_timer,SIGNAL(timeout()),this,SLOT(m_timer_timeout()));
    for(int i = 0; i<10; i++)
    {
        connect(itemList[i],SIGNAL(clicked(int)),this,SLOT(itemclick(int)));
        //void (pageButton::*signalPtr)(int) = &pageButton::entered;  //信号指针,指向pageButton的enterd信号,我这里就不这样写了
        connect(qobject_cast<PageButton *>(m_buttonGroup->button(i)),SIGNAL(clicked(int)),this,SLOT(buttonEnterd(int)));
        //使用cast转换成自定义按钮类型
    }
}

void CircularBannerWidget::setPixmapList()
{
    for (int i = 0; i < 10; i++)
    {
        QString pixPath = QString(":/images/homeTab/recommend/homeBanner/banner%1.png").arg(i);
        QPixmap pix = QPixmap(pixPath);
        pix = pix.scaled(ui->bannerGraphicsView->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
        //这句我也不知道有啥用,我试了去掉也没什么变化,可能图片的大小刚刚好,如果图片大小不合适的话就会出问题,还是加上合适
        itemList.append(new BannerItem(pix));
        itemList[i]->setScale(m_PixmapScaleList[i]);
        itemList[i]->setIndex(i);
        itemList[i]->setOffset(QPointF(0,0));
    }
}

void CircularBannerWidget::addBannerItem()
{
    for(int i = 0; i<10; i++)
    {
        m_bannerScene->addItem(itemList[i]);//添加图元
        itemList[i]->setTransformationMode(Qt::SmoothTransformation);//设置缩放模式
        itemList[i]->setPos(m_pointList[i]);//设置位置
        itemList[i]->setZValue(m_ZValueList[i]);//设置显示优先级
    }
}

void CircularBannerWidget::initAnimationAndTimeline()
{
    m_itemAnimation = QVector<QGraphicsItemAnimation *>(10);
    m_timeline = new QTimeLine(300); //动画在多长时间完成,默认为1000,就是1秒
    m_timeline->setLoopCount(1);//设置1次
    for (int i = 0; i < 10; i++)
    {
        m_itemAnimation[i] = new QGraphicsItemAnimation();
        m_itemAnimation[i]->setItem(itemList[i]);
        m_itemAnimation[i]->setTimeLine(m_timeline);
    }



}

void CircularBannerWidget::itemclick(int itemIndex)
{
    emit ItemLink(itemIndex);
    //这里由于有item重叠,点中间项的时候会点到两个项,如果写if(itemIndex == m_currentItemIndex)不可行
    //我这里也不知道怎么搞,就先这样写,以后有时间再看看
    return;

}

void CircularBannerWidget::bannerRun()
{
    m_timeline->stop();
    int index = m_firstItemIndex;
    for (int i = 0; i<10; i++,index++)
    {
    index = indexMap(index);
    itemList[index]->setTransformationMode(Qt::SmoothTransformation);//设置缩放模式
    itemList[index]->setZValue(m_ZValueList[i]);//设置显示优先级
    itemList[index]->setScale(m_PixmapScaleList[i]);
    //itemList[index]->setPos(m_pointList[i]);
    m_itemAnimation[index]->setPosAt(0.6,m_pointList[i]);
    }
    m_timeline->start();
    m_timer->start(); //重新从0计时
    m_buttonGroup->button(m_currentItemIndex)->setChecked(true);

}

int CircularBannerWidget::indexMap(int index)
{
    if(index == 10)
    {
        index = 0;
    }
    if(index == -1)
    {
       index = 9;
    }
    return index;
}

void CircularBannerWidget::m_timer_timeout()
{
    m_lastItemIndex = m_firstItemIndex;
    m_firstItemIndex = m_currentItemIndex;
    m_currentItemIndex = indexMap(m_currentItemIndex+1);
    bannerRun();
}

void CircularBannerWidget::buttonEnterd(int index)
{
    m_currentItemIndex = index;
    m_firstItemIndex = indexMap(index-1);
    m_lastItemIndex = indexMap(m_firstItemIndex-1);
    bannerRun();
}


void CircularBannerWidget::on_lButton_clicked()
{
    m_currentItemIndex = m_firstItemIndex;
    m_firstItemIndex = m_lastItemIndex;
    m_lastItemIndex = indexMap(m_lastItemIndex-1);
    bannerRun();
}


void CircularBannerWidget::on_rButton_clicked()
{
    m_lastItemIndex = m_firstItemIndex;
    m_firstItemIndex = m_currentItemIndex;
    m_currentItemIndex = indexMap(m_currentItemIndex+1);
    bannerRun();
}

然后我这里是参考了博客https://blog.csdn.net/weixin_42126427/article/details/121083770?spm=1001.2014.3001.5502
以及
https://blog.csdn.net/h391998495979/article/details/101868838
的代码,只是我取其精华去其糟粕了,把好多多余的地方都删掉了,不过还是感谢两位,大家也可以参考下

大家喜欢我的博客,可以关注我,感谢大家的支持

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值