Qt之Model-View架构

Qt之Model-View架构

简述

为什么会用这个模式,这里我就不解释了,可以看下 豆子哥的见解 。这里我只是如何去使用的。供大家共同探讨学习,主要是参考了Qt的Demo。

效果图

这里写图片描述

代码

//主代码界面QMvcTest.cpp
void QMvcTest::initControl()
{
    QCustomItemModel* customModel = new QCustomItemModel(QJsonArray(), ui.treeView);
    ItemDelegate *delegate = new ItemDelegate(ui.treeView);
    ui.treeView->setModel(customModel);
    delegate->setView(ui.treeView);
    ui.treeView->setAnimated(true);
    ui.treeView->setMouseTracking(true);
    ui.treeView->setItemDelegate(delegate);
    ui.treeView->setCursor(Qt::PointingHandCursor);

    const QModelIndex&& curIndex = customModel->index(0, 0).child(0, 0);
    ui.treeView->setCurrentIndex(curIndex);
    connect(delegate, SIGNAL(expanded(const QModelIndex &)), this, SLOT(onTreeViewExpanded(const QModelIndex &)));
}

void QMvcTest::onTreeViewExpanded(const QModelIndex &index)
{
    bool bExpanded = ui.treeView->isExpanded(index);
    if (!bExpanded)
    {
        ui.treeView->expand(index);
    }
    else
    {
        ui.treeView->collapse(index);
    }
}
//QCustomItemModel.cpp
QCustomItemModel::QCustomItemModel(const QJsonArray &data, QObject *parent)
    : QAbstractItemModel(parent)
{
    QJsonArray objChildArray = { QStringLiteral("雨田哥1号"), QStringLiteral("雨田哥2号"), QStringLiteral("雨田哥3号"), QStringLiteral("雨田哥4号"), QStringLiteral("雨田哥5号") };
    QJsonObject obj{ { QStringLiteral("雨田哥"), objChildArray }
    };
    QJsonArray array = { obj, obj, obj };

    QVector<QVariant> rootData;
    rootData << "";
    rootItem = new TreeItem(rootData);
    setModelData(array);
}

QCustomItemModel::~QCustomItemModel()
{
    delete rootItem;
}

int QCustomItemModel::columnCount(const QModelIndex & /* parent */) const
{
    return rootItem->columnCount();
}

int QCustomItemModel::rowCount(const QModelIndex &parent) const
{
    TreeItem *parentItem = getItem(parent);
    return parentItem->childCount();
}

QVariant QCustomItemModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    TreeItem *item = getItem(index);
    if (item == nullptr)
    {
        return QVariant();
    }

    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        return item->data(index.column());
    }
    else if (role == Qt::UserRole + 1)
    {
        //是否是子节点
        if (item->childCount() == 0)
        {
            return true;
        }
        return false;
    }
    else
    {
        return QVariant();
    }
}

Qt::ItemFlags QCustomItemModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;
    TreeItem *item = getItem(index);
    if (item && item->childCount() > 0)
    {
        return Qt::NoItemFlags;
    }
    return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

TreeItem *QCustomItemModel::getItem(const QModelIndex &index) const
{
    if (index.isValid()) {
        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
        if (item)
            return item;
    }
    return rootItem;
}

QVariant QCustomItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
        return rootItem->data(section);

    return QVariant();
}

QModelIndex QCustomItemModel::index(int row, int column, const QModelIndex &parent) const
{
    if (parent.isValid() && parent.column() != 0)
        return QModelIndex();
    TreeItem *parentItem = getItem(parent);

    TreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

bool QCustomItemModel::insertColumns(int position, int columns, const QModelIndex &parent)
{
    bool success;

    beginInsertColumns(parent, position, position + columns - 1);
    success = rootItem->insertColumns(position, columns);
    endInsertColumns();

    return success;
}

bool QCustomItemModel::insertRows(int position, int rows, const QModelIndex &parent)
{
    TreeItem *parentItem = getItem(parent);
    bool success;

    beginInsertRows(parent, position, position + rows - 1);
    success = parentItem->insertChildren(position, rows, rootItem->columnCount());
    endInsertRows();

    return success;
}

QModelIndex QCustomItemModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    TreeItem *childItem = getItem(index);
    TreeItem *parentItem = childItem->parent();

    if (parentItem == rootItem)
        return QModelIndex();

    return createIndex(parentItem->childNumber(), 0, parentItem);
}

bool QCustomItemModel::removeColumns(int position, int columns, const QModelIndex &parent)
{
    bool success;

    beginRemoveColumns(parent, position, position + columns - 1);
    success = rootItem->removeColumns(position, columns);
    endRemoveColumns();

    if (rootItem->columnCount() == 0)
        removeRows(0, rowCount());

    return success;
}

bool QCustomItemModel::removeRows(int position, int rows, const QModelIndex &parent)
{
    TreeItem *parentItem = getItem(parent);
    bool success = true;

    beginRemoveRows(parent, position, position + rows - 1);
    success = parentItem->removeChildren(position, rows);
    endRemoveRows();

    return success;
}

bool QCustomItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::EditRole)
    {
        TreeItem *item = getItem(index);
        bool result = item->setData(index.column(), value);

        if (result)
            emit dataChanged(index, index);
        return result;
    }
    else if (role == Qt::FontRole)
    {
        TreeItem *item = getItem(index);
        if (item && item->childCount() == 0)
        {
            item->m_itemFontIsBold = value.toBool();
        }
        return true;
    }
    else
    {
        return false;
    }
}

bool QCustomItemModel::setHeaderData(int section, Qt::Orientation orientation,
                              const QVariant &value, int role)
{
    if (role != Qt::EditRole || orientation != Qt::Horizontal)
        return false;

    bool result = rootItem->setData(section, value);

    if (result)
        emit headerDataChanged(orientation, section, section);

    return result;
}

void QCustomItemModel::setModelData(const QJsonArray &data)
{
    for (int nRootIndex = 0; nRootIndex < data.size(); nRootIndex++)
    {
        const QJsonObject&& obj = data.at(nRootIndex).toObject();
        for (auto itor = obj.begin(); itor != obj.end(); itor++)
        {
            const QString&& key = itor.key();
            const QJsonArray&& childAray = itor.value().toArray();

            QVector<QVariant> columnData;
            columnData << key;
            rootItem->insertChildren(nRootIndex, 1, rootItem->columnCount());

            TreeItem* parent = rootItem->child(nRootIndex);
            parent->setData(0, key);

            for (int index = 0; index < childAray.size(); index++)
            {
                parent->insertChildren(index, 1, rootItem->columnCount());
                parent->child(index)->setData(0, childAray.at(index).toString());
            }
        }
    }
}
//TreeItem.cpp
TreeItem::TreeItem(const QVector<QVariant> &data, TreeItem *parent)
{
    m_itemFontIsBold = true;
    parentItem = parent;
    itemData = data;
}

TreeItem::~TreeItem()
{
    qDeleteAll(childItems);
}

TreeItem *TreeItem::child(int number)
{
    return childItems.value(number);
}

int TreeItem::childCount() const
{
    return childItems.count();
}

int TreeItem::childNumber() const
{
    if (parentItem)
        return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

    return 0;
}

int TreeItem::columnCount() const
{
    return itemData.count();
}

QVariant TreeItem::data(int column) const
{
    return itemData.value(column);
}

bool TreeItem::insertChildren(int position, int count, int columns)
{
    if (position < 0 || position > childItems.size())
        return false;

    for (int row = 0; row < count; ++row) {
        QVector<QVariant> data(columns);
        TreeItem *item = new TreeItem(data, this);
        childItems.insert(position, item);
    }

    return true;
}

bool TreeItem::insertColumns(int position, int columns)
{
    if (position < 0 || position > itemData.size())
        return false;

    for (int column = 0; column < columns; ++column)
        itemData.insert(position, QVariant());

    foreach (TreeItem *child, childItems)
        child->insertColumns(position, columns);

    return true;
}

TreeItem *TreeItem::parent()
{
    return parentItem;
}

bool TreeItem::removeChildren(int position, int count)
{
    if (position < 0 || position + count > childItems.size())
        return false;

    for (int row = 0; row < count; ++row)
        delete childItems.takeAt(position);

    return true;
}

bool TreeItem::removeColumns(int position, int columns)
{
    if (position < 0 || position + columns > itemData.size())
        return false;

    for (int column = 0; column < columns; ++column)
        itemData.remove(position);

    foreach (TreeItem *child, childItems)
        child->removeColumns(position, columns);

    return true;
}

bool TreeItem::setData(int column, const QVariant &value)
{
    if (column < 0 || column >= itemData.size())
        return false;

    itemData[column] = value;
    return true;
}
//ItemDelegate.cpp
void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem  viewOption(option);
    QStyledItemDelegate::paint(painter, viewOption, index);

    bool bExpanded = false;
    if (m_treeView != NULL)
    {
        const QAbstractItemModel *model = index.model();
        if (!model->hasChildren(index))
        {
            return;
        }
        bExpanded = m_treeView->isExpanded(index);
    }

    QPixmap pixmap = bExpanded ? QPixmap(m_expandIconName) : QPixmap(m_collapseIconName);
    QRect decorationRect = QRect(viewOption.rect.left() + 14, viewOption.rect.top() + 12, m_pixmapHeight, m_pixmapWidth);
    painter->drawPixmap(decorationRect, pixmap);
}

bool ItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    if (event->type() == QEvent::MouseButtonPress && Qt::LeftButton == qApp->mouseButtons())
    {
        m_treeView->update();
        emit expanded(index);
    }
    return QStyledItemDelegate::editorEvent(event, model, option, index);
}

void ItemDelegate::setView(QTreeView *treeView)
{
    m_treeView = treeView;
}
//QSS样式
QTreeView
{
    background-color: #ffffff;
    show-decoration-selected: 1;
    outline:0px;
}

QTreeView::item {
    background-color:transparent;
    font-family: Microsoft YaHei;
    font-size: 12px;
    color: #666666;
    text-align:left;
    height:32px;
    padding-left:22px;
}

QTreeView::item:has-children {
    background-color:transparent;
    font-family: Microsoft YaHei;
    font-size: 12px;
    color: #333333;
    text-align:left;
    height:32px;
    padding-left:22px;
}

QTreeView::item:hover,QTreeView::item:selected {
    background-color:#D3EFFF;
    font-size: 12px;
    color: #00A1FF;
    border:0px;
    text-align:left;
}

QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
    border-image: none;
    image: url(:/QMvcTest/Resources/smallPackup.png:);
}

QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings  {
    border-image: none;
    image: url(:/QMvcTest/Resources/smallExp.png);
}

结尾

只为记录,只为分享! 愿所写能对你有所帮助。不忘记点个赞,谢谢~
需要原工程文件的可以加我QQ,因权限问题暂时不能上传工程文件。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨田哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值