在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_OBJECT
public:
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_NAMESPACE
class MCSTListItemWidget : public QWidget
{
Q_OBJECT
public:
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-1008
int m_channelId; //2001-2008
QString m_selectFzdModel; //M1-M8
float 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-1008
recipeDataInfo->m_channelId; //2001-2008
recipeDataInfo->m_selectFzdModel = "M1"; //M1-M8
recipeDataInfo->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; //ms
recipeDataInfo->m_ivTestInterval = 3000; //ms
recipeDataInfo->m_ivSamplePointCount = 30; //default 30
recipeDataInfo->m_mpptAdjustInterval = 5 * 1000;//ms
recipeDataInfo->m_testTotalTime = 1 * 60 * 60 * 1000; //ms
recipeDataInfo->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,绑定右侧数据