Qt-MVC架构

目录

何为

just do it

Care

Qes


 

Qt可作为数据可视化的一种解决方案。对此,常用的就是mvc架构了。较与常规wiget填充展示数据层次更加清晰。

何为

具体看下图

数据源:首先我们需要定制适合的数据结构,用个容器进行包裹即可

src_model:对于不同的view需要不同的model,我们对应继承并重写相关方法即可

proxy_model:代理model,用src_model作为model源;负责过滤【淘汰方法】{filterAcceptsRow,filterAcceptsColumn

}和排序【排序方法】{lessThan}

proxy_ui:代理ui,使用designer设计的ui,view最终展示的item

item_delegate:view的item代理,负责paint、create我们的proxy_ui

至于,这几者数据交互,基本由index和role完成

just do it

实现的效果

A图:数据从无到有的,添加过程,addData()

B图:更新数据,checkAble,

C图:实现排序

D图:编辑item

如何实现的呢,这里列出基本结构

  • Model
// data
typedef  struct _info{

    QString name;
    QString sex ;
    bool protect;
    QString desc;
    bool checkable;
    _info(){
        name = "";
        sex = "";
        protect = false;
        desc = "hello";
        checkable = false;
    }
} Info;
Q_DECLARE_METATYPE(Info)

// model
class MyModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit MyModel(QObject *parent = nullptr);
    MyModel(const MyModel &other);
    ~MyModel();

    // data 层面更新原始数据
    void updateDaTa(const bool &checkabale);
    // data 层面添加数据
    void addData(QString const &name, QString const &sex, bool protect = false);

    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;

    // 对于不同角色getData
    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    // model 填充数据
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);

    // 角色名
    virtual QHash<int, QByteArray> roleNames() const;
    // 对应的item选项 care
    virtual Qt::ItemFlags flags(const QModelIndex &index) const;

private:
    // 数据源
    QList<Info> m_data;
};
Q_DECLARE_METATYPE(MyModel)
void MyModel::updateDaTa(const bool &checkabale)
{
    beginResetModel();
    // data
    for(auto &one : m_data){
        one.checkable = checkabale;
    }
    // core update model
    endResetModel();
}

int MyModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_data.length();
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || rowCount() < index.row() || index.row() < 0)
        return QVariant();

    int row = index.row();
    Info item = m_data[row];
    switch (role) {
    case Qt::UserRole:
        return item.name;
    case Qt::UserRole+1:
        return item.sex;
    case Qt::UserRole+2:
        return item.protect;
    case Qt::UserRole+3:
        return item.desc;
    case Qt::UserRole+4:
        return item.checkable;
    default:
        break;
    }
    return QVariant();
}

QHash<int, QByteArray> MyModel::roleNames() const
{
    QHash<int,QByteArray> hash;
    hash.insert(Qt::UserRole, "name");
    hash.insert(Qt::UserRole+1, "sex");
    hash.insert(Qt::UserRole+2, "protect");
    hash.insert(Qt::UserRole+3, "desc");
    hash.insert(Qt::UserRole+4, "checkable");
    return hash;
}

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role == Qt::UserRole+3)
    {
        m_data[index.row()].desc = value.toString();
        emit dataChanged(index, index);
        return true;
    }
    if (index.isValid() && role == Qt::UserRole+4)
    {
        m_data[index.row()].checkable = value.toBool();
        emit dataChanged(index, index);
        return true;
    }
    return false;
}

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

void MyModel::addData(const QString &name, const QString &sex, bool protect)
{
    Info item;
    item.name = name;
    item.sex = sex;
    item.protect = protect;
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_data << item;
    endInsertRows();
}
  • proxy_model
bool SortProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
    QString sexLeft = left.data(Qt::UserRole+1).toString();
    QString sexRight = right.data(Qt::UserRole+1).toString();
    // M > F
    if(sexLeft>sexRight){
        return true;
    }
    else if(sexLeft == sexRight){
        return left.data(Qt::UserRole).toString() > right.data(Qt::UserRole).toString();
    }
    else{
        return false;
    }
}
  • itemDelegate
#define USE_HELP qDebug() << __FUNCTION__;

MyDelegate::MyDelegate(QObject *p)
    :QStyledItemDelegate(p)
{
    m_pDeleWidget = new DelegateWgt();
}

MyDelegate::~MyDelegate()
{
    m_pDeleWidget->deleteLater();
    m_pDeleWidget = nullptr;
}


void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if(m_misEdit)
    {
        if(m_mEditingIndex == index)
        {
            return QStyledItemDelegate::paint(painter, option, index);
        }
    }

    QString name = index.data(Qt::UserRole).toString();
    QString sex = index.data(Qt::UserRole+1).toString();
    bool protect = index.data(Qt::UserRole+2).toBool();
    QString desc = index.data(Qt::UserRole+3).toString();
    bool checkable = index.data(Qt::UserRole+4).toBool();

    m_pDeleWidget->setName(name);
    m_pDeleWidget->setSex(sex);
    m_pDeleWidget->setProtect(protect);
    m_pDeleWidget->setDesc(desc);
    m_pDeleWidget->setCheckable(checkable);

    m_pDeleWidget->resize(option.rect.size());
    painter->save();
    QPixmap pixmap(m_pDeleWidget->size());
    m_pDeleWidget->render(&pixmap);
    painter->drawPixmap(option.rect,pixmap);
    painter->restore();

    QStyledItemDelegate::paint(painter, option, index);
}


QSize MyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    return QSize(100,70);
}


QWidget *MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    USE_HELP
    m_misEdit = true;
    m_mEditingIndex = index;

    DelegateWgt *deleGateWgt = new DelegateWgt(parent);
    deleGateWgt->resize(option.rect.size());
    return deleGateWgt;
}

void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    USE_HELP
    DelegateWgt *srcWgt = static_cast<DelegateWgt*>(editor);
    if(srcWgt){
        QString name = index.data(Qt::UserRole).toString();
        QString sex = index.data(Qt::UserRole+1).toString();
        bool protect = index.data(Qt::UserRole+2).toBool();
        QString desc = index.data(Qt::UserRole+3).toString();
        bool checkable = index.data(Qt::UserRole+4).toBool();

        srcWgt->setName(name);
        srcWgt->setSex(sex);
        srcWgt->setProtect(protect);
        srcWgt->setDesc(desc);
        srcWgt->setCheckable(checkable);
    }
}

void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    USE_HELP
    DelegateWgt *srcWgt = static_cast<DelegateWgt*>(editor);
    if(srcWgt){
        model->setData(index, srcWgt->getName(), Qt::UserRole);
        model->setData(index, srcWgt->getSex(), Qt::UserRole+1);
        model->setData(index, false, Qt::UserRole+2);
        model->setData(index,srcWgt->getDesc(),Qt::UserRole+3);
        model->setData(index, srcWgt->getCheckable(), Qt::UserRole+4);
    }
    m_misEdit = false;
}

void MyDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    USE_HELP
    DelegateWgt *srcWgt = static_cast<DelegateWgt*>(editor);
    if(srcWgt){
        srcWgt->setGeometry(option.rect);
    }
}
  • 代理ui

其就是传统designer设计的widget即可

  • using
    // model
    m_pModel = new MyModel;
    // proxy_model
    m_pSortModelProxy = new SortProxy;
    m_pSortModelProxy->setSourceModel(m_pModel);

    // itemDelegat
    m_pDelegate = new MyDelegate;

    // view
    ui->listView->setModel(m_pSortModelProxy);
    ui->listView->setItemDelegate(m_pDelegate);

    // add
    m_pModel->addData
    // updata
    m_pModel->updateDaTa
    // sort
    m_pSortModelProxy->sort(0)

Care

其实,主要是对于Qt这种mvc架构中index和role的理解,主要model中的这几个函数,数据导向是一个怎样的情况。

Qes

如何,实现类widget那样直接可以编辑item,即可见即可编辑?

 


版权声明:本文为qq_39175540原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。