翻譯|使用教程|編輯:周思宇|2023-05-26 11:55:38.023|閱讀 160 次
概述:本章講述Qt可編輯樹模型的示例(三),歡迎閱讀~
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
Qt 是目前最先進、最完整的跨平臺C++開發工具。它不僅完全實現了一次編寫,所有平臺無差別運行,更提供了幾乎所有開發過程中需要用到的工具。如今,Qt已被運用于超過70個行業、數千家企業,支持數百萬設備及應用。
The Qt Company是Digia Plc旗下的全資子公司。負責所有Qt活動,包括產品開發,商業和開源授權模式以及在開放管理模式下的Qt工程。其許可、支持和服務能力能夠和開發者緊密合作以確保他們的Qt項目準時部署,不超預算并擁有競爭優勢。
Qt技術交流群:166830288
該TreeModel類提供了一個實現QAbstractItemModel類,為可以編輯和調整大小的模型公開必要的接口。
class TreeModel : public QAbstractItemModel { Q_OBJECT public: TreeModel(const QStringList &headers, const QString &data, QObject *parent = nullptr); ~TreeModel();
構造函數和析構函數是特定于這個模型的。
QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override;
只讀樹模型只需要提供以上功能即可。以下公共函數提供對編輯和調整大小的支持:
Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; bool insertColumns(int position, int columns, const QModelIndex &parent = QModelIndex()) override; bool removeColumns(int position, int columns, const QModelIndex &parent = QModelIndex()) override; bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override; bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override; private: void setupModelData(const QStringList &lines, TreeItem *parent); TreeItem *getItem(const QModelIndex &index) const; TreeItem *rootItem; };
為了簡化這個示例,模型公開的數據通過模型的setupModelData()函數組織到一個數據結構中。許多現實世界的模型根本不會處理原始數據,而只是使用現有的數據結構或庫API。
構造函數創建一個根項并使用提供的標頭數據對其進行初始化:
TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent) : QAbstractItemModel(parent) { QList<QVariant> rootData; for (const QString &header : headers) rootData << header; rootItem = new TreeItem(rootData); setupModelData(data.split('\n'), rootItem); }
調用內部的setupModelData()函數,將提供的文本數據轉換為可以與模型一起使用的數據結構。其他模型可以使用現成的數據結構進行初始化,或者使用維護自己數據的庫中的API。
析構函數只需刪除根項,這將導致遞歸刪除所有子項。
TreeModel::~TreeModel() { delete rootItem; }
由于模型到其他模型/視圖組件的接口是基于模型索引的,并且由于內部數據結構是基于項的,因此模型實現的許多函數需要能夠將任何給定的模型索引轉換為相應的項。為了方便和一致性,我們定義了一個getItem()函數來執行這個重復的任務:
TreeItem *TreeModel::getItem(const QModelIndex &index) const { if (index.isValid()) { TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); if (item) return item; } return rootItem; }
傳遞給此函數的每個模型索引都應對應于內存中的有效項目。如果索引無效,或其內部指針未指向有效項,則返回根項。
該模型的rowCount()實現很簡單:首先使用函數getItem()獲取相關項;然后返回它所包含的子項的個數:
int TreeModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() && parent.column() > 0) return 0; const TreeItem *parentItem = getItem(parent); return parentItem ? parentItem->childCount() : 0; }
相比之下,columnCount()實現不需要查找特定項目,因為所有項目都被定義為具有相同數量的與其關聯的列。
int TreeModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return rootItem->columnCount(); }
因此,可以直接從根項中獲取列數。
為了使項目能夠被編輯和選擇,需要實現flags()函數,以便它返回標志的組合,包括Qt::ItemIsEditable和Qt::ItemIsSelectable標志以及Qt::ItemIsEnabled。
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEditable | QAbstractItemModel::flags(index); }
該模型需要能夠生成模型索引,以允許其他組件請求有關其結構的數據和信息。該任務由index()函數執行,該函數用于獲取與給定父項的子項對應的模型索引:
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() && parent.column() != 0) return QModelIndex();
在此模型中,如果父索引無效(對應于根項)或列號為零,我們僅返回子項的模型索引。
我們使用自定義getItem()函數來獲取與所提供的模型索引對應的TreeItem實例,并請求與指定行對應的其子項。
TreeItem *parentItem = getItem(parent); if (!parentItem) return QModelIndex(); TreeItem *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); return QModelIndex(); }
由于每項都包含一整行數據的信息,因此我們創建一個模型索引,通過調用createIndex()來唯一地標識它,方法是使用行號和列號以及指向該項目的指針。在data()函數中,我們將使用項目指針和列號來訪問與模型索引相關的數據;在此模型中,不需要行號來標識數據。
parent()函數通過查找給定模型索引的相應項,使用它的parent()函數獲得它的父項,然后創建一個模型索引來表示父項,從而為項的父項提供模型索引。(如圖所示)。
QModelIndex TreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = getItem(index); TreeItem *parentItem = childItem ? childItem->parent() : nullptr; if (parentItem == rootItem || !parentItem) return QModelIndex(); return createIndex(parentItem->childNumber(), 0, parentItem); }
沒有父項的項(包括根項)通過返回空模型索引來處理。否則,將像index()函數一樣創建并返回一個模型索引,并使用合適的行號,但列號為零,與index()實現中使用的方案一致。
歡迎下載|體驗更多Qt產品
獲取更多信息請咨詢 ;Qt技術交流群:166830288
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn