QT之动态加载下拉框(QComboBox)
- 简介
- 效果
- 原理分析
- 实现
简介
这两天遇到一个需求,需要下拉选项中动态加载一些数据,实现之后感觉挺有意思,特此记录一下。
效果
还是先看下效果,源码也放在文末了
原理分析
要实现此类效果,要拆解下功能项:
- 第一步,下拉选项的item要能够显示动态图片
- 第二步,拦截ComboBox的鼠标事件,使得再点击特定得节点后可以执行一些额外得操作,并且不隐藏下拉框
实现
分解了功能点,接下来就可以实现代码了:
首先让QListWidgetItem能够显示动态图标,QT控件得setIcon接口原生是不支持显示动态图片的,那怎么实现呢?
我的方法是,封装一个MyListWidgetItem类,类成员包含QListWidgetItem,并且使用QMovie播放gif图片,获取每帧并实时更新Icon。实现代码如下:
Ps:有大佬有更好的办法望指教
ListWidgetItem.h
#ifndef ListWidgetItem_H
#define ListWidgetItem_H
#include <QObject>
#include <QIcon>
#include <QMovie>
#include <QTimer>
class QListWidgetItem;
class ListWidgetItem : public QObject
{
Q_OBJECT
public:
explicit ListWidgetItem(const QString& text,QObject *parent = nullptr);
explicit ListWidgetItem(const QIcon& _icon,const QString& text,QObject *parent = nullptr);
~ListWidgetItem();
void setGifPath(const QString& path);
QListWidgetItem* getItem();
void start();
void stop();
protected slots:
void slot_timeOut();
private:
void connectAll();
private:
QListWidgetItem *m_item = nullptr;
QIcon m_icon;
QString m_gifPath;
QTimer m_timer;
QMovie m_movie;
};
#endif // ListWidgetItem_H
ListWidgetItem.cpp
#include "ListWidgetItem.h"
#include <QListWidgetItem>
#include <QApplication>
ListWidgetItem::ListWidgetItem(const QString &text, QObject *parent)
: QObject(parent)
{
m_item = new QListWidgetItem(text);
m_item->setData(Qt::UserRole+1,qint64(this));
connectAll();
}
ListWidgetItem::ListWidgetItem(const QIcon &_icon, const QString &text, QObject *parent) : QObject(parent)
{
m_item = new QListWidgetItem(_icon,text);
m_item->setData(Qt::UserRole+1,qint64(this));
m_icon = _icon;
connectAll();
}
ListWidgetItem::~ListWidgetItem()
{
}
void ListWidgetItem::setGifPath(const QString &path)
{
m_gifPath = path;
m_movie.setFileName(m_gifPath);
}
QListWidgetItem *ListWidgetItem::getItem()
{
return m_item;
}
void ListWidgetItem::start()
{
// m_movie.setSpeed(100);
m_movie.start();
m_timer.start(30);
}
void ListWidgetItem::stop()
{
m_movie.stop();
m_timer.stop();
m_item->setIcon(m_icon);
}
void ListWidgetItem::slot_timeOut()
{
if(nullptr == m_item)
{
return;
}
QPixmap pix = m_movie.currentPixmap();
m_item->setIcon(pix);
// m_timer.stop();
}
void ListWidgetItem::connectAll()
{
connect(&m_timer,&QTimer::timeout,this,&ListWidgetItem::slot_timeOut);
}
然后,过滤ComboBox的鼠标事件,并实现播放动画和其他操作,实现方式为:
重写QComboBox,并为其view()->viewport()安装事件过滤器,监听鼠标弹起事件QEvent::MouseButtonRelease。关键代码如下
DynamicBox::DynamicBox(QWidget *parent)
: QComboBox(parent)
{
if(this->view() != nullptr)
{
this->view()->installEventFilter(this);
this->view()->viewport()->installEventFilter(this);
}
}
bool DynamicBox::eventFilter(QObject *o, QEvent *e)
{
auto index = this->view()->currentIndex();
if(e->type() == QEvent::MouseButtonRelease && index.data().toString() == "加载更多")
{
auto item = static_cast<QListWidgetItem*>(index.internalPointer());
if(nullptr == item)
{
return false;
}
auto Myitem = (ListWidgetItem*)(item->data(Qt::UserRole+1).toLongLong());
if(nullptr == Myitem)
{
return false;
}
Myitem->start();
QTimer::singleShot(3000,this,[Myitem,this](){
Myitem->stop();
emit signal_test(this);
});
return true;
}
return QComboBox::eventFilter(o,e);
}
做完这些后就能实现图中效果啦~
源码下载在这里