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,因权限问题暂时不能上传工程文件。