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_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,绑定右侧数据
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值