栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

(Qt)封装下链式结构(QListView)的MVC(MVD)用法

(Qt)封装下链式结构(QListView)的MVC(MVD)用法

对于一些数据量小的列表我们使用QListWidget往往能满足开发的需求,但是对于大数据量的展示来说(几十万,上百万)来说的话,全部加载是一个不是很合适的方法。因此我们使用MVC,这里可能应该叫MVD(model,view,delegation)。这样做个人认为有两个好处:

1.效率问题,view和delegation配合只负责从model中取显示需要的数据,因此带来高效。

2.model的数据可以由不同view来显示。

这里的话封装下通用QListView的通用方法(Tree和Table之后做),去除其中一些不必要业务逻辑(有空我自己精简下,目前没时间),可作为通用模板使用,基本就是三个类,有不明白的可以私信我。

一.View :.h文件

/// @brief 视图
class PreviewLeftWin:public QListView
{
	Q_OBJECT
public:
	PreviewLeftWin(QWidget* parent = 0);
	~PreviewLeftWin();
	void   Initialize();                               //总体初始化
	void   InitUi();                                   //初始化Ui
	void   SwitchStyleSheet();                         //设置样式表
	void   ClearViewData();                            //清空当前视图的数据
	void   LoadData(QVector>, QSharedPointer);  //加载数据,丙切换选择到某数据

private:
	virtual void startDrag(Qt::DropActions supportedActions) Q_DECL_OVERRIDE;     //开始拖拽事件
	virtual void mousePressEvent(QMouseEvent* e);                                 //鼠标按下事件

signals:
	void SigShowResource(QSharedPointer);   //选中项改变通知外部改变

private:
	PreviewLeftWinModel*         m_model;     //模型
	PreviewLeftWinItemDelegate*  m_delegate;  //委托
	BFScrollBar*                 m_bfscroll;  //滚动条

private slots:
	virtual void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
};

View:cpp文件

PreviewLeftWin::PreviewLeftWin(QWidget* parent ) :QListView(parent)
{
	this->Initialize();
}

PreviewLeftWin::~PreviewLeftWin()
{

}

void PreviewLeftWin::Initialize()
{
	//初始化UI
	this->InitUi();
	//初始化Model
	m_model = new PreviewLeftWinModel(this);
	this->setModel(m_model);
	//初始化委托
	m_delegate = new PreviewLeftWinItemDelegate(this);
	this->setItemDelegate(m_delegate);
}

void PreviewLeftWin::InitUi()
{
	setAttribute(Qt::WA_TranslucentBackground, false);
	setAcceptDrops(false);
	setDragDropMode(QAbstractItemView::NoDragDrop);
	setDragEnabled(false);
	setDropIndicatorShown(false);
	setMouseTracking(true);
	setAutoFillBackground(true);
	setRowHidden(0, true);
	setViewMode(QListView::ListMode);
	setResizeMode(QListView::Adjust);
	setMovement(QListView::Snap);
	setSelectionMode(QAbstractItemView::SingleSelection);

	//样式表
	this->SwitchStyleSheet();

	//搭载自定义滚动条
	m_bfscroll = new BFScrollBar(Qt::Vertical, this);
	m_bfscroll->SetScrollArea(this);
}

void PreviewLeftWin::SwitchStyleSheet()
{
	QString _bkStyle = QString("QListView{border:none;background-color:rgba(0,0,0,0);}QListView::item:selected{background-color:rgba(0,0,0,0);border:0px solid;}");
	setStyleSheet(_bkStyle);
}

void PreviewLeftWin::ClearViewData()
{
	//model赋值数据
	m_model->ClearData();
	//刷新结构
	doItemsLayout();
	//刷新
	this->update();
}

void PreviewLeftWin::LoadData(QVector>iphoto_vec, QSharedPointeripoto)
{
	//读取新数据
	m_model->ClearData();
	m_model->SetUserData(iphoto_vec);

	this->clearSelection();


	//切换到选择的那个
	int index = iphoto_vec.indexOf(ipoto);
	QModelIndex qindex = m_model->index(index, 0);
    this->setCurrentIndex(qindex);

	//滚动条也要跟上
}

void PreviewLeftWin::startDrag(Qt::DropActions supportedActions)
{
	return;
}

void PreviewLeftWin::mousePressEvent(QMouseEvent* e)
{
	this->update();
	return QListView::mousePressEvent(e);
}

void PreviewLeftWin::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
{
	//获取当前选中的
	QModelIndexList index_list = selected.indexes();

	if (index_list.isEmpty())
	{
		//第一次可能为空
		return;
	}

	if (index_list.size() != 1)
	{
		Q_ASSERT(0);
		return;
	}
	QModelIndex cur_index = index_list[0];


	QSharedPointer iphoto = cur_index.data(PreviewLeftWinModel_Data).value< QSharedPointer >();
	if (!iphoto)
	{
		Q_ASSERT(0);
	}
	SigShowResource(iphoto);
}

二.model:.h文件

class PreviewLeftWinModel : public QAbstractListModel
{
	Q_OBJECT
public:
   PreviewLeftWinModel(QObject* parent);
   ~PreviewLeftWinModel();

public:
	void ClearData(); //清空数据结构
	void SetUserData(QVector>);//设置用户数据

private:
   virtual QVariant data(const QModelIndex &index, int role) const;
   virtual Qt::ItemFlags  flags(const QModelIndex& index) const;
   virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
   virtual QVariant headerData(int section, Qt::Orientation orientation,int role = Qt::DisplayRole) const;
   virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
   virtual int columnCount(const QModelIndex& parent) const;
private:
	QVector> m_data_vec;
};

 model:.cpp文件

PreviewLeftWinModel::PreviewLeftWinModel(QObject* parent)
{
	ClearData();
}

PreviewLeftWinModel::~PreviewLeftWinModel()
{

}

void PreviewLeftWinModel::ClearData()
{
	m_data_vec.clear();
}

void PreviewLeftWinModel::SetUserData(QVector>datas)
{
	m_data_vec = datas;
}

//



QVariant PreviewLeftWinModel::data(const QModelIndex &index,int role) const
{
	//无数据
	if (m_data_vec.size()==NULL)
	{
        return QVariant();
    }

	//无效节点
    if( !index.isValid())
	{
        return QVariant();
    }
	
	//数据结构对应index(容器index)
    int row_index = index.row();

	if (row_index > m_data_vec.size() - 1)
	{
		return QVariant();
	}

	//↓↓↓↓↓↓↓↓↓取数据↓↓↓↓↓↓↓↓↓↓
	if (role == PreviewLeftWinModel_Data)
    {
	    //取素材数据
		QSharedPointer photo = m_data_vec.at(row_index);
		if ( photo != NULL ) 
		{			
			return QVariant::fromValue(photo);
		}
		else
		{
			return QVariant(0);
		}
	}
	return QVariant();
}

Qt::ItemFlags PreviewLeftWinModel::flags(const QModelIndex& index) const
{
	return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
		Qt::ItemIsEditable ;
}

bool PreviewLeftWinModel::setData(const QModelIndex &index,const QVariant &value, int role)
{
	return true;
}

QVariant PreviewLeftWinModel::headerData(int section, Qt::Orientation orientation,int role ) const
{
	return QVariant();
}

int PreviewLeftWinModel::rowCount(const QModelIndex &parent ) const
{
	return m_data_vec.size();
}

int PreviewLeftWinModel::columnCount(const QModelIndex& parent) const
{
	return 1;
}

三.Delegate:.h文件

/// @brief 委托
class PreviewLeftWinItemDelegate : public QStyledItemDelegate {
	Q_OBJECT

public:
	PreviewLeftWinItemDelegate(QObject* parent = 0);
	virtual ~PreviewLeftWinItemDelegate();
	void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
	bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index);
	QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
	void setEditorData(QWidget* editor, const QModelIndex& index) const;
	QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;

private:
	//类似网格布局需要根据rect_image来进一步适配
	QRect GetimageRect(QRect, QSize) const;
};

Delegate:.cpp文件

PreviewLeftWinItemDelegate::PreviewLeftWinItemDelegate(QObject* parent )
{

}

PreviewLeftWinItemDelegate::~PreviewLeftWinItemDelegate()
{

}

void PreviewLeftWinItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	//先判断下该项是否被选中
	bool is_select = false;
	if (option.state & QStyle::State_Selected)
	{
		is_select = true;
	}

    //取数据
	QSharedPointer iphoto = index.data(PreviewLeftWinModel_Data).value< QSharedPointer >();
	if (!iphoto)
	{
		Q_ASSERT(0);
	}

	//取区域大小
	QRect item_rect = option.rect.adjusted(10,10,-10,-10);

	if (is_select)
	{
		item_rect= option.rect.adjusted(22, 2, -22, -2);
	}
	else
	{
		item_rect = option.rect.adjusted(33, 10, -33, -10);
	}

	//选中的话画一下选中的边框
	if (is_select)
	{
		painter->save();
		QPen pen;
		pen.setColor(BFSkinSetting::GetInstance()->GetCommonFirstColor());
		pen.setWidth(2);
		painter->setPen(pen);
		painter->drawRect(item_rect.adjusted(-3, -3, 3, 3));
		painter->restore();
	}


	//取图片尺寸
	QSize image_size = QSize(100,100);
	if (iphoto)
	{
		if (RESOURCE_TYPE == iphoto->m_phototype)
		{
			IBFSource* cur_resource = iphoto->m_pIBFResource;
			if (cur_resource)
			{
				const uint32_t iWidth = static_cast(reinterpret_cast(cur_resource->GetValue(BF_SOURCE_TYPE_WIDTH)));
				const uint32_t iHeight = static_cast(reinterpret_cast(cur_resource->GetValue(BF_SOURCE_TYPE_HEIGHT)));

				if ((iWidth > 0) && (iHeight > 0))
				{
					image_size = QSize(iWidth, iHeight);
				}
				else
				{
					image_size = QSize(100, 100);
				}
			}
		}
	}

	//得到图片实际区域
	QRect image_rect = GetimageRect(item_rect, image_size);

	//在最开始设置3个反走样选项,之后不用再设置,只需设置颜色
	painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);

	//绘制
    //配置painter
	painter->setPen(Qt::NoPen);
	painter->setBrush(Qt::NoBrush);

	//根据文件是否隐藏,变更显示透明度
	if (iphoto->GetHide())
		painter->setOpacity(0.3);
	else
		painter->setOpacity(1.0);


	//是否支持解析
	bool analysis = CAppSingleton::getInstance()->GetSourceIsAnalysis(iphoto->m_pIBFResource);
	//是否解析成功
	bool anaSuc = (SourceWidth(iphoto->m_pIBFResource) != 0) && (SourceHeight(iphoto->m_pIBFResource) != 0);


	//1、索引素材且路径没有丢失;2、支持解析的素材,解析成功  3.解析失败  4.存在webp缩略图文件
	bool b1 = iphoto->GetIndexValid();
	bool b2 = analysis && anaSuc;
	bool b3 = !analysis;
	bool b4 = false;
	QString strPathName = iphoto->GetThumbnail();
	if (strPathName.endsWith(".webp") && QFileInfo::exists(strPathName))
	{
		b4 = true;
	}


	if ((b1 && b2) || (b3 && b4))
	{
		QString cachekey = iphoto->GetCacheKey();
		QPixmap pixmap;
		if (!QPixmapCache::find(cachekey, &pixmap))
		{
			if (!iphoto.isNull()) {
				QRect grid_image_rect = image_rect;
				// 没找到缓存 cachemanager 去加载缓存
				BFCacheManager::GetInstance()->AddPhote(iphoto.data(),
														grid_image_rect.size());

				//connect(BFCacheManager::GetInstance(),
				//		&BFCacheManager::sigThumbnailLoad, this,
				//		&GridItem::slotThumbnailLoad, Qt::UniqueConnection);
			}
			//没取到图片,根据色域表取值
			if (!iphoto->ResIsNull())
			{
				int iCnt = 5;
				PSCOLOR pClr = iphoto->m_pIBFResource->GetColours(&iCnt);
				QColor clr;
				if (pClr) {
					clr.setRgb(pClr[2].clr.R, pClr[2].clr.G, pClr[2].clr.B);
				}
				else {
					clr = BFBackGroundColorGet();
				}
				painter->fillRect(image_rect,QBrush(QColor(clr)));
				painter->setBrush(QColor(clr));
				painter->drawRoundedRect(image_rect, 10, 10,
										 Qt::AbsoluteSize);
			}
			else
			{
				painter->fillRect(image_rect,
								  QBrush(BFBackGroundColorGet()));
				painter->setBrush(BFBackGroundColorGet());
				painter->drawRoundedRect(image_rect, 10, 10,
										 Qt::AbsoluteSize);
			}
		}
		else
		{
			QRect grid_image_rect = image_rect;
			const int64_t iType = iphoto->GetType();
			if (CAppSingleton::getInstance()->isAudioResource(iType))
			{
				// 音频特殊处理
				painter->setBrush(QColor(162, 171, 195));
				painter->drawRoundedRect(grid_image_rect, 4, 4, Qt::AbsoluteSize);
				painter->drawPixmap(grid_image_rect, pixmap);
			}
			else
			{
				painter->drawPixmap(grid_image_rect, pixmap);
			}
		}
	}
	//如果 索引素材路径丢失 ,显示【索引素材路径丢失图片】
	else if (!iphoto->GetIndexValid())
	{
		QString pix_str = BFSkinSetting::GetInstance()->GetResourceAbsolutePath("file_index_lose.svg");
		QSvgRenderer  svg_render(pix_str);
		QSize default_size = svg_render.defaultSize();
		QPixmap need_pix(default_size.width() * g_fGlobalDPI, default_size.height() * g_fGlobalDPI);
		need_pix.fill(Qt::transparent);//设置背景透明
		QPainter p(&need_pix);
		svg_render.render(&p);

		//索引丢失背景
		painter->setBrush(QColor("#6A748B"));
		painter->drawRoundedRect(image_rect, 4, 4);

		//索引丢失图片
		QSize pic_size = default_size;
		QRect item_image_rect = image_rect;
		int icon_x = item_image_rect.x() + (item_image_rect.width() - pic_size.width()) / 2;
		int icon_y = item_image_rect.y() + (item_image_rect.height() - pic_size.height()) / 2;
		painter->drawPixmap(icon_x, icon_y, pic_size.width(), pic_size.height(), need_pix);
	}
	//如果是 【支持导入的文件,不支持分析】
	else if (!analysis)
	{
		//画背景色 
		painter->setBrush(BFSkinSetting::GetInstance()->GetMainColor());
		painter->drawRoundedRect(image_rect, 10, 10);

		//计算文字
		QFont font;
		font.setFamily("Microsoft YaHei");
		font.setPixelSize(20);
		font.setBold(true);
		QString typeStr = CAppSingleton::getInstance()->GetSourceType(iphoto->m_pIBFResource);
		typeStr = BFQtUtils::FontAdjustWidth(font, image_rect.width(), typeStr);
		int fontWidth = BFQtUtils::WidthWithFixString(font, typeStr);
		QFontMetrics fms(font);
		int fontHeight = fms.height() + 10;

		int text_width = fontWidth;
		int text_height = fontHeight;
		int text_x = image_rect.x() + (image_rect.width() - text_width) / 2;
		int text_y = image_rect.y() + (image_rect.height() - text_height) / 2;

		QRect text_rect = QRect(text_x, text_y, text_width, text_height);

		painter->setPen(BFSkinSetting::GetInstance()->GetTextColor(0));
		painter->setFont(font);
		painter->drawText(text_rect, typeStr);
	}
	//其他情况,比如解析失败或者支持解析但是没有缩略图
	else
	{
		int imageWidth = 320;
		int imageHeight = (imageWidth * image_rect.height()) / image_rect.width();
		QImage defaultImage(imageWidth, imageHeight, QImage::Format_ARGB32);
		QPainter ImagePainter(&defaultImage);
		ImagePainter.setBrush(QColor("#FFE6E6E6"));
		ImagePainter.drawRect(defaultImage.rect());

		QFont font;
		font.setFamily("Microsoft YaHei");
		font.setPixelSize(50);
		font.setBold(true);
		QString typeStr = CAppSingleton::getInstance()->GetSourceType(iphoto->m_pIBFResource);
		typeStr = BFQtUtils::FontAdjustWidth(font, 320, typeStr);
		int fontWidth = BFQtUtils::WidthWithFixString(font, typeStr);
		QFontMetrics fms(font);
		int fontHeight = fms.height() + 10;

		//计算文字位置,设置字体并绘制。
		QPoint textTopLeftPoint((defaultImage.width() - fontWidth) / 2, (defaultImage.height() - fontHeight) / 2);
		QRect fontRect(textTopLeftPoint, QSize(fontWidth, fontHeight));
		ImagePainter.setFont(font);
		ImagePainter.setPen(QColor("#0FB1B9"));
		ImagePainter.drawText(fontRect, Qt::AlignCenter, typeStr);

		QPixmap need_pixmap = QPixmap::fromImage(defaultImage);
		BFQtUtils::SetPixmapToRound(need_pixmap, need_pixmap.size(), 10);
		painter->drawImage(image_rect, defaultImage);
	}
}

bool PreviewLeftWinItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
{
	return QStyledItemDelegate::editorEvent(event,model,option,index);
}

QWidget* PreviewLeftWinItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	return NULL;
	//return QStyledItemDelegate::createEditor(parent, option, index);
}

void PreviewLeftWinItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{

}

QSize PreviewLeftWinItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	return QSize(0, PreviewLeftWinItemHeight);
}

QRect PreviewLeftWinItemDelegate::GetimageRect(QRect all_rect,QSize ori_size) const
{
//算出宽高比
	float rate = (float)ori_size.width() / ori_size.height();
	float now_rect_rate = (float)all_rect.width() / all_rect.height();

	QSize need_size = QSize();
	//左上角点
	int x_pos = 0;
	int y_pos = 0;

	if (rate >= now_rect_rate)
	{
		//宽图;图片宽比大于容器宽比,则图片宽设置为容器宽,再求图片高
		int image_width = all_rect.width();
		int image_height = image_width / rate;
		need_size = QSize(image_width, image_height);

		//算下新左上角点
		x_pos = all_rect.topLeft().x();
		y_pos = all_rect.topLeft().y() + (all_rect.height() - image_height) / 2;
	}
	else
	{
		//高图;图片宽比小于容器宽比,则图片高设置为容器高,再求图片宽
		int image_height = all_rect.height();
		int image_width = image_height * rate;
		need_size = QSize(image_width, image_height);

		//算下新左上角点
		x_pos = all_rect.topLeft().x() + (all_rect.width() - image_width) / 2;
		y_pos = all_rect.topLeft().y();
	}

	//转换为rect内部矩形
	QRect need_rect = QRect(QPoint(x_pos, y_pos), need_size);
	return need_rect;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/601442.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号