QLisview 实现model deletage,并且在不需要编辑的情况下自定义UI
在QListView中自定义model、deletage,普遍是使用paint函数绘制;
如果要使用自己的自定义QWidget,比如利用ui文件和子当以类创建一个自定义的Item,如何再QListView中实现。
核心代码:
为新项启用持久编辑器 重中之重
ui->listView->openPersistentEditor(m_listModel->index(i));
以下用一个QListView的例子实现上述情景
自定义模型文件
#pragma execution_character_set("utf-8")
#ifndef MULTICHANNELTESTSYSTEM_MCSTRECIPELISTMODEL_H
#define MULTICHANNELTESTSYSTEM_MCSTRECIPELISTMODEL_H#include <QObject>
#include <QAbstractListModel>
#include <QAbstractItemModel>
class MCSTRecipeConfigDataStr;class MCSTRecipeListModel : public QAbstractListModel
{Q_OBJECTpublic:MCSTRecipeListModel(QObject *parent = nullptr);~MCSTRecipeListModel();
public:// 返回行数int rowCount(const QModelIndex& parent = QModelIndex()) const override;// 获取数据QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;// 设置数据bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;Qt::ItemFlags flags(const QModelIndex& index) const override;
public:// 添加数据项void insertData(QSharedPointer<MCSTRecipeConfigDataStr>);
private:QList<QSharedPointer<MCSTRecipeConfigDataStr>> m_recipeDataList;
};//cpp文件
#include "MCSTRecipeListModel.h"
#include "MCSTData.hpp"
MCSTRecipeListModel::MCSTRecipeListModel(QObject *parent): QAbstractListModel(parent)
{
}MCSTRecipeListModel::~MCSTRecipeListModel()
{
}// 返回行数
int MCSTRecipeListModel::rowCount(const QModelIndex& parent) const
{return m_recipeDataList.size();
}// 获取数据
QVariant MCSTRecipeListModel::data(const QModelIndex& index, int role) const
{QVariant variantRet;int row = index.row();if (row >= m_recipeDataList.size() || (!index.isValid())){return QVariant();}auto item = m_recipeDataList.at(row);if (role == Qt::UserRole) {variantRet = QVariant::fromValue<const QSharedPointer<MCSTRecipeConfigDataStr>>(item);return variantRet;} else if (role == Qt::UserRole + 1) {return QVariant();} return QVariant();
}// 设置数据
bool MCSTRecipeListModel::setData(const QModelIndex& index, const QVariant& configData,int role)
{bool ret = false;int row = index.row();qDebug() << "setData row:" << row <<" data size:"<< m_recipeDataList.size();if (row >= m_recipeDataList.size() || (!index.isValid())){qDebug() << "setData index avalid" ;return ret;}switch (role) {case Qt::UserRole: {auto data = configData.value<QSharedPointer<MCSTRecipeConfigDataStr>>();//m_recipeDataList[row] = data;m_recipeDataList[row]->m_recipeName = data->m_recipeName;m_recipeDataList[row]->m_recipeModifyTime = data->m_recipeModifyTime;m_recipeDataList[row]->m_recipeType = data->m_recipeType;m_recipeDataList[row]->m_recipePath = data->m_recipePath;ret = true;}break;case Qt::UserRole + 1: {}break;case Qt::UserRole + 2: {}break;default:break;}//发送信号触发刷新//emit dataChanged(index, index, QVector<int>() << role);emit dataChanged(index, index, { role }); // 通知数据变化return ret;
}Qt::ItemFlags MCSTRecipeListModel::flags(const QModelIndex& index) const
{return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
}void MCSTRecipeListModel::insertData(QSharedPointer<MCSTRecipeConfigDataStr> data)
{int r = m_recipeDataList.size();qDebug() << "insertData r:" << r<<",rowCount"<< this->rowCount();beginInsertRows(QModelIndex(), this->rowCount(), this->rowCount());m_recipeDataList.push_back(data);endResetModel();
}
自定义代理文件
#pragma execution_character_set("utf-8")
#ifndef MULTICHANNELTESTSYSTEM_MCSTRECIPELISTDELETAGE_H
#define MULTICHANNELTESTSYSTEM_MCSTRECIPELISTDELETAGE_H#include <QObject>
#include <QLineEdit>
#include <QWidget>
#include <QObject>
#include <QModelIndex>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QStyleOptionViewItem>
#include <QAbstractItemModel>class MCSTListItemWidget;class MCSTRecipeListDeletage : public QStyledItemDelegate
{Q_OBJECT
public:explicit MCSTRecipeListDeletage(QObject *parent = nullptr);~MCSTRecipeListDeletage();protected:QWidget* createEditor(QWidget* parent,const QStyleOptionViewItem& option,const QModelIndex& index) const override;void setEditorData(QWidget* editor, const QModelIndex& index) const override;void setModelData(QWidget* editor,QAbstractItemModel* model,const QModelIndex& index)const override;void updateEditorGeometry(QWidget* editor,const QStyleOptionViewItem& option,const QModelIndex& index)const override;QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;//处理鼠标事件bool editorEvent(QEvent* event,QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)override;
};//代理文件CPP#include "MCSTRecipeListDeletage.h"
#include "MCSTListItemWidget.h"
#include <MCSTData.hpp>MCSTRecipeListDeletage::MCSTRecipeListDeletage(QObject *parent): QStyledItemDelegate(parent)
{}MCSTRecipeListDeletage::~MCSTRecipeListDeletage()
{
}QWidget* MCSTRecipeListDeletage::createEditor(QWidget* parent,const QStyleOptionViewItem& option,const QModelIndex& index) const
{// 从 Model 获取数据//auto data = index.data(Qt::UserRole).value<QSharedPointer<MCSTRecipeConfigDataStr>>();MCSTListItemWidget* widget = new MCSTListItemWidget(parent);//widget->setRecipeName(data->m_recipeName);//widget->setRecipeDate(data->m_recipeModifyTime);//widget->setRecipePath(data->m_recipePath);//widget->setRecipeType(data->m_recipeType);qDebug() << "createEditor";return widget;
}void MCSTRecipeListDeletage::setEditorData(QWidget* editor, const QModelIndex& index)const
{ MCSTListItemWidget* widget = qobject_cast<MCSTListItemWidget*>(editor);if (widget == nullptr)return;qDebug() << "setEditorData";// 从模型中获取结构体数据QSharedPointer<MCSTRecipeConfigDataStr> data = index.model()->data(index, Qt::UserRole).value<QSharedPointer<MCSTRecipeConfigDataStr>>();qDebug() << "setEditorData name:"<< data->m_recipeName;qDebug() << "setEditorData modifyTime:" << data->m_recipeModifyTime;qDebug() << "setEditorData recipeType:" << data->m_recipeType;qDebug() << "setEditorData recipePath:" << data->m_recipePath;widget->setRecipeName(data->m_recipeName);widget->setRecipeDate(data->m_recipeModifyTime);widget->setRecipeType(data->m_recipeType);widget->setRecipePath(data->m_recipePath);
}void MCSTRecipeListDeletage::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index)const
{MCSTListItemWidget* widget = qobject_cast<MCSTListItemWidget*>(editor); if (widget == nullptr)return;qDebug() << "setModelData";//从编辑器中获取数据信息QSharedPointer<MCSTRecipeConfigDataStr> data(new MCSTRecipeConfigDataStr);data->m_recipeName = widget->getRecipeName() ;data->m_recipeModifyTime = widget->getRecipeDate() ;data->m_recipeType = widget->getRecipeType() ;data->m_recipePath = widget->getRecipePath() ;// 设置模型中的数据model->setData(index,QVariant::fromValue<QSharedPointer<MCSTRecipeConfigDataStr>>(data),Qt::UserRole);
}void MCSTRecipeListDeletage::updateEditorGeometry(QWidget* editor,const QStyleOptionViewItem& option,const QModelIndex& index)const
{editor->setGeometry(option.rect);
}QSize MCSTRecipeListDeletage::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{// 调用基类的 sizeHint 方法获取原始大小QSize size = QStyledItemDelegate::sizeHint(option, index);// 修改高度为 50 像素size.setHeight(55);return size;
}bool MCSTRecipeListDeletage::editorEvent(QEvent* event,QAbstractItemModel* model,const QStyleOptionViewItem& option,const QModelIndex& index)
{return MCSTRecipeListDeletage::editorEvent(event, model,option,index);
}
自定义ListView Item
#pragma execution_character_set("utf-8")
#ifndef MULTICHANNELTESTSYSTEM_MCSTLISTITEMWIDGET_H
#define MULTICHANNELTESTSYSTEM_MCSTLISTITEMWIDGET_H#include <QWidget>
#include "ui_MCSTRecipeListItemWidget.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MCSTRecipeListItemWidget; };
QT_END_NAMESPACEclass MCSTListItemWidget : public QWidget
{Q_OBJECTpublic:MCSTListItemWidget(QWidget *parent = nullptr);~MCSTListItemWidget();
public:void setRecipeName(const QString &);void setRecipeDate(const QString&);void setRecipeType(const QString&);void setRecipePath(const QString&);QString getRecipeName()const;QString getRecipeDate()const;QString getRecipeType()const;QString getRecipePath()const;
private:Ui::MCSTRecipeListItemWidget *ui;
private:QString m_recipePath;
};#include "MCSTListItemWidget.h"MCSTListItemWidget::MCSTListItemWidget(QWidget *parent): QWidget(parent), ui(new Ui::MCSTRecipeListItemWidget())
{ui->setupUi(this);
}MCSTListItemWidget::~MCSTListItemWidget()
{delete ui;
}void MCSTListItemWidget::setRecipeName(const QString& name)
{ui->lineEdit->setText(name);
}
void MCSTListItemWidget::setRecipeDate(const QString& date)
{ui->lineEdit_2->setText(date);
}
void MCSTListItemWidget::setRecipeType(const QString& Type)
{ui->label_3->setText(Type);
}
void MCSTListItemWidget::setRecipePath(const QString& path)
{m_recipePath = path;
}QString MCSTListItemWidget::getRecipeName()const
{return ui->lineEdit->text();
}
QString MCSTListItemWidget::getRecipeDate()const
{return ui->lineEdit_2->text();
}
QString MCSTListItemWidget::getRecipeType()const
{return ui->label_3->text();
}
QString MCSTListItemWidget::getRecipePath()const
{return m_recipePath;
}#endif
数据结构
class MCSTCalcSaveData : public QObject
{
Q_OBJECT
public:explicit MCSTCalcSaveData(QObject* parent = nullptr): QObject(parent){};~MCSTCalcSaveData() override = default;public:QVector<float> m_voltageData{};QVector<float> m_circuteData{};QVector<double> m_fzdData{};int m_modelId{};int m_channelId{};int m_dataType{-1};int m_sampleTime{-1};double m_powerData{0.00f};double m_deviceTempture{0.00};};
Q_DECLARE_METATYPE(QSharedPointer<MCSTCalcSaveData>)class MCSTRecipeDataInfoStr :public QObject
{Q_OBJECT
public:explicit MCSTRecipeDataInfoStr(QObject* parent = nullptr) : QObject(parent) {};~MCSTRecipeDataInfoStr() override = default;public:int m_modelId; //1001-1008int m_channelId; //2001-2008QString m_selectFzdModel; //M1-M8float m_fzdAdjustFactor;float m_voltageLevel;float m_circuteLevel;float m_startVoltage;float m_finalVoltage;int m_ivScanTime;int m_ivTestInterval;int m_ivSamplePointCount;int m_mpptAdjustInterval;int m_testTotalTime;int m_channelEnable;
};
Q_DECLARE_METATYPE(MCSTRecipeDataInfoStr)
Q_DECLARE_METATYPE(QSharedPointer<MCSTRecipeDataInfoStr>)class MCSTRecipeConfigDataStr:public QObject
{Q_OBJECT
public:explicit MCSTRecipeConfigDataStr(QObject* parent = nullptr) : QObject(parent) {};~MCSTRecipeConfigDataStr() override = default;
public:bool isApply;QString m_recipeName;QString m_recipeModifyTime;QString m_recipeType;QString m_recipePath;//[1001,[2001,data]]--->[modelId,[channelId,data]]QMap<int, QMap<int, QSharedPointer<MCSTRecipeDataInfoStr>>> m_recipeDataInfoMap;};
Q_DECLARE_METATYPE(MCSTRecipeConfigDataStr)
Q_DECLARE_METATYPE(QSharedPointer<MCSTRecipeConfigDataStr>)
调用方法:
m_listModel = new MCSTRecipeListModel;m_listDelegate = new MCSTRecipeListDeletage;ui->listView->setModel(m_listModel);ui->listView->setItemDelegate(m_listDelegate);ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers); // 禁用默认编辑QSharedPointer<MCSTRecipeConfigDataStr> recipeListItem(new MCSTRecipeConfigDataStr);
if (recipeType == ActionType::IV)
{recipeListItem->m_recipeType = "IV";
}
else if (recipeType == ActionType::MPPT)
{recipeListItem->m_recipeType = "MPPT";
}
else if (recipeType == ActionType::IV_MPPT)
{recipeListItem->m_recipeType = "IV_MPPT";
}//创建 M1-M5 CH1-CH8的配方数据 现在默认是5*8 = 40个
for (auto model : model_codes)
{for (int index = 0;index <8;index++) {auto modelId = model;auto channelId = channel_codes[index];QSharedPointer<MCSTRecipeDataInfoStr> recipeDataInfo(new MCSTRecipeDataInfoStr);recipeDataInfo->m_modelId; //1001-1008recipeDataInfo->m_channelId; //2001-2008recipeDataInfo->m_selectFzdModel = "M1"; //M1-M8recipeDataInfo->m_fzdAdjustFactor = m_default_fzd_factor;recipeDataInfo->m_voltageLevel = test_voltage_level.first().toFloat();recipeDataInfo->m_circuteLevel = test_current_level.first().toFloat();recipeDataInfo->m_startVoltage = -1.0f;recipeDataInfo->m_finalVoltage = 1.0f;recipeDataInfo->m_ivScanTime = 100; //msrecipeDataInfo->m_ivTestInterval = 3000; //msrecipeDataInfo->m_ivSamplePointCount = 30; //default 30recipeDataInfo->m_mpptAdjustInterval = 5 * 1000;//msrecipeDataInfo->m_testTotalTime = 1 * 60 * 60 * 1000; //msrecipeDataInfo->m_channelEnable = 0;QMap<int, QSharedPointer<MCSTRecipeDataInfoStr>> channelData;channelData[channelId] = recipeDataInfo;recipeListItem->m_recipeDataInfoMap[modelId] = channelData;}
}qDebug() << "createRecipe";recipeListItem->m_recipeName = tr("testRecipe");recipeListItem->m_recipeModifyTime = MCSTGenerateUUID::UUIDTime(); recipeListItem->m_recipePath = QString::fromStdString(MCSTData::getBinPath() + "/cache/"+recipeListItem->m_recipeName.toStdString() + ".json");m_listModel->insertData(recipeListItem);// 为新项启用持久编辑器 重中之重int row = m_listModel->rowCount();for (int i = 0; i < row; ++i) {ui->listView->openPersistentEditor(m_listModel->index(i));
}
以上就实现了下方的功能,左侧自定义listView,绑定右侧数据