Qt轮播图动画实现

目录

  • Qt轮播图动画实现

Qt轮播图动画实现

轮播图在网页上挺常见的,在Qt中可以用属性动画来实现。

需要注意几点

  • 计算好需要移动图片的始末位置
  • 在合适的时候将要显示的图片添加到布局,并将要消失的图片移除布局
  • 动画结束时,把消失的图片删除
  • 当动画还没结束,又有新的动作时,应马上结束动画开始新动作

看代码。
wheelwidget.h

#pragma once
#include "QObject"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "ui_wheelwidget.h"
#include "QParallelAnimationGroup"
#include 

//轮播图类,实现轮播效果
class wheelwidget : public QWidget
{
	Q_OBJECT

public:
	wheelwidget(QWidget *parent = Q_NULLPTR);
	~wheelwidget();
public slots:
	void addItem(QFileInfo fileinfo);
	void puticeChanged(int row);

private:
	void startAnimation();
	Ui::wheelwidget ui;
	QButtonGroup* m_pButtonGroup;
	QSize m_iconSize;
	QParallelAnimationGroup* m_pAnimGroup;
	int m_iDuration = 1000; //动画持续时间
	int m_ipreRow = 0;
	QWidget* m_pShouleDel = nullptr;
	QEasingCurve::Type m_eEasingCurve = QEasingCurve::OutBounce;
	QString m_PituceDirPath = u8"H:/秦时明月/";
};


//文件读取类
class readPuticeFile : public QObject
{
	Q_OBJECT

public:
	readPuticeFile(QObject* parent = nullptr)
		:QObject(parent)
	{

	}
	void setDirPath(QString path) { m_DirPath = path; }

signals:
	void sigAddItem(QFileInfo fileinfo);
	void sigOver();

public slots:
	void startRead()
	{
		qDebug() << QThread::currentThreadId();
		QDir dir(u8"H:/秦时明月/");
		auto filelist = dir.entryInfoList();
		for (auto& file : filelist)
		{
			emit sigAddItem(file);
// 			QThread::msleep(100);
		}
		emit sigOver();
	}
private:
	QString m_DirPath;
};

wheelwidget.cpp

#include "wheelwidget.h"
#include 
#include 
#include 

wheelwidget::wheelwidget(QWidget *parent)
	: QWidget(parent),
	m_iconSize(100, 100)
{
	ui.setupUi(this);
	ui.listWidget->setIconSize(m_iconSize);
	readPuticeFile* r = new readPuticeFile();
	r->setDirPath(m_PituceDirPath);
	QThread* t = new QThread();
	r->moveToThread(t);//移到另一个线程
	connect(t, &QThread::started, r, &readPuticeFile::startRead);
	connect(r, &readPuticeFile::sigAddItem, this, &wheelwidget::addItem, Qt::QueuedConnection); //必须加上最后一个参数,不然崩溃
	connect(r, &readPuticeFile::sigOver, t, &QThread::quit);
	t->start();
	connect(ui.listWidget, &QListWidget::currentRowChanged,
		this, &wheelwidget::puticeChanged);
	m_pAnimGroup = new QParallelAnimationGroup();
	ui.spinBox->setValue(m_iDuration);
	connect(ui.spinBox, QOverload<int>::of(&QSpinBox::valueChanged), [=](int i) {m_iDuration = i; });
	const QMetaObject& mo = QEasingCurve::staticMetaObject;
	QMetaEnum metaEnum = mo.enumerator(mo.indexOfEnumerator("Type"));
	// Skip QEasingCurve::Custom
	for (int i = 0; i < QEasingCurve::NCurveTypes - 1; ++i) {
		QListWidgetItem* item = new QListWidgetItem;
		item->setText(metaEnum.key(i));
		ui.listWidget_2->addItem(item);
	}
	connect(ui.listWidget_2, &QListWidget::currentRowChanged, [=](int row) {m_eEasingCurve = (QEasingCurve::Type) row; });

}

wheelwidget::~wheelwidget()
{
}

void wheelwidget::startAnimation()
{
}

void wheelwidget::addItem(QFileInfo fileinfo)
{
	QListWidgetItem* item = new QListWidgetItem;
	qDebug() << fileinfo.absoluteFilePath();
	item->setIcon(QIcon(fileinfo.absoluteFilePath()));
	item->setText(fileinfo.fileName());
	item->setTextAlignment(Qt::AlignBottom | Qt::AlignLeft);//设置对齐方式
	ui.listWidget->addItem(item);
}

void wheelwidget::puticeChanged(int row)
{
	if (m_pAnimGroup->state() == QAbstractAnimation::Running)
	{
		m_pAnimGroup->setCurrentTime(m_iDuration); //如果动画还在运行,立即完成
	}
	auto item = ui.listWidget->currentItem();
	QString filename = item->text();
	QPixmap pix(m_PituceDirPath + filename);
	auto layout = ui.widget->layout();
	QWidget* preLabel = layout->takeAt(0)->widget();	//先从布局中拿出来
	m_pShouleDel = preLabel;
	pix.scaled(preLabel->size(), Qt::KeepAspectRatio);
	QLabel* nlabel = new QLabel(this);
	nlabel->setPixmap(pix);

	QPropertyAnimation *animation = new QPropertyAnimation(preLabel, "geometry");
	animation->setDuration(m_iDuration);
	animation->setStartValue(preLabel->geometry());
	animation->setEasingCurve(m_eEasingCurve);
	QPropertyAnimation* newanimation = new QPropertyAnimation(nlabel, "geometry");
	newanimation->setDuration(m_iDuration);
	newanimation->setEndValue(preLabel->geometry());
	newanimation->setEasingCurve(m_eEasingCurve);
	if (row > m_ipreRow)	//从右向左移动
	{
		QPoint np(0 - preLabel->width() - ui.widget->x(), preLabel->y());	//计算
		animation->setEndValue(QRect(np, preLabel->size()));
		QPoint nlp(preLabel->x() + preLabel->width(), preLabel->y());
		newanimation->setStartValue(QRect(nlp, preLabel->size()));
	}
	else //从左向右移动
	{
		QPoint np(preLabel->x() + ui.widget->width(), preLabel->y());	//计算
		animation->setEndValue(QRect(np, preLabel->size()));
		QPoint nlp(preLabel->x() - preLabel->width(), preLabel->y());
		newanimation->setStartValue(QRect(nlp, preLabel->size()));
	}
	m_ipreRow = row;
	m_pAnimGroup->addAnimation(animation);
	m_pAnimGroup->addAnimation(newanimation);
	qDebug() << u8"动画数\t" << m_pAnimGroup->animationCount();
	qDebug() << layout->count();
	layout->addWidget(nlabel); //加入布局
	connect(m_pAnimGroup, &QParallelAnimationGroup::finished, [=]() {
		m_pShouleDel->deleteLater();	//删除移除了的图片
		while (m_pAnimGroup->animationCount())
		{
			qDebug() << m_pAnimGroup->animationCount();
			auto anim = dynamic_cast<QPropertyAnimation*>(m_pAnimGroup->takeAnimation(0));
			anim->deleteLater();
		}
	});
	m_pAnimGroup->start();
}

wheelwidget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>wheelwidget</class>
 <widget class="QWidget" name="wheelwidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>766</width>
    <height>578</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>wheelwidget</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,2">
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout" stretch="5,1">
     <item>
      <widget class="QListWidget" name="listWidget">
       <property name="flow">
        <enum>QListView::LeftToRight</enum>
       </property>
      </widget>
     </item>
     <item>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item>
        <widget class="QListWidget" name="listWidget_2"/>
       </item>
       <item>
        <widget class="QSpinBox" name="spinBox">
         <property name="maximum">
          <number>10000</number>
         </property>
        </widget>
       </item>
      </layout>
     </item>
    </layout>
   </item>
   <item>
    <widget class="QWidget" name="widget" native="true">
     <layout class="QVBoxLayout" name="verticalLayout_2">
      <item>
       <widget class="QLabel" name="label">
        <property name="text">
         <string>TextLabel</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
  </layout>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

以上代码在qt5.14.1 和vs2019上编译运行。

你可能感兴趣的:(Qt)