翻譯|使用教程|編輯:龔雪|2023-02-24 10:17:22.760|閱讀 221 次
概述:本教程將為大家介紹每個UI開發人員都應該了解的ModelView編程,歡迎下載相關組件體驗~
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
每個UI開發人員都應該了解ModelView編程,本教程的目標是為大家提供一個簡單易懂的介紹。
Qt 是目前最先進、最完整的跨平臺C++開發工具。它不僅完全實現了一次編寫,所有平臺無差別運行,更提供了幾乎所有開發過程中需要用到的工具。如今,Qt已被運用于超過70個行業、數千家企業,支持數百萬設備及應用。
在上文中,我們主要為大家介紹了如何創建一個簡單的Model/View(模型/視圖)的應用(點擊這里回顧>>),本文將繼續為大家介紹如何實現中間主題。
Qt技術交流群:166830288 歡迎一起進群討論
開發人員可以將上面的示例轉換為具有樹視圖的應用程序,簡單地將 替換為,這將產生一個讀/寫樹。不必對模型進行任何更改,樹不會有任何層次結構,因為模型本身沒有任何層次結構。
QListView、QTableView和QTreeView都使用一個模型抽象,它是一個合并的列表、表和樹,這使得從同一個模型中使用幾種不同類型的視圖類成為可能。
這是我們的示例模型到目前為止的樣子:
為了建立一個模型,我們把數據封裝在上面的示例中。這次使用QStandardItemModel,它是一個層次數據的容器,也實現了QAbstractItemModel。要顯示樹,QStandardItemModel必須用QStandardItems填充,QStandardItems能夠容納項目的所有標準屬性,如文本、字體、復選框或筆刷。
(文件來源:examples/widgets/tutorials/modelview/6_treeview/mainwindow.cpp)
// modelview.cpp #include "mainwindow.h" #include <QTreeView> #include <QStandardItemModel> #include <QStandardItem> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , treeView(new QTreeView(this)) , standardModel(new QStandardItemModel(this)) { setCentralWidget(treeView); QList<QStandardItem *> preparedRow = prepareRow("first", "second", "third"); QStandardItem *item = standardModel->invisibleRootItem(); // adding a row to the invisible root item produces a root element item->appendRow(preparedRow); QList<QStandardItem *> secondRow = prepareRow("111", "222", "333"); // adding a row to an item starts a subtree preparedRow.first()->appendRow(secondRow); treeView->setModel(standardModel); treeView->expandAll(); } QList<QStandardItem *> MainWindow::prepareRow(const QString &first, const QString &second, const QString &third) const { return {new QStandardItem(first), new QStandardItem(second), new QStandardItem(third)}; }
我們簡單地實例化一個,并向構造函數添加兩個,然后可以創建一個層次數據結構,因為一個 可以容納其他,節點在視圖中折疊和展開。
我們希望訪問選定項的內容,以便將其與層次結構級別一起輸出到窗口標題中。
所以創建兩個項目:
(文件來源:examples/widgets/tutorials/modelview/7_selections/mainwindow.cpp)
#include "mainwindow.h" #include <QTreeView> #include <QStandardItemModel> #include <QItemSelectionModel> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , treeView(new QTreeView(this)) , standardModel(new QStandardItemModel(this)) { setCentralWidget(treeView); auto *rootNode = standardModel->invisibleRootItem(); // defining a couple of items auto *americaItem = new QStandardItem("America"); auto *mexicoItem = new QStandardItem("Canada"); auto *usaItem = new QStandardItem("USA"); auto *bostonItem = new QStandardItem("Boston"); auto *europeItem = new QStandardItem("Europe"); auto *italyItem = new QStandardItem("Italy"); auto *romeItem = new QStandardItem("Rome"); auto *veronaItem = new QStandardItem("Verona"); // building up the hierarchy rootNode-> appendRow(americaItem); rootNode-> appendRow(europeItem); americaItem-> appendRow(mexicoItem); americaItem-> appendRow(usaItem); usaItem-> appendRow(bostonItem); europeItem-> appendRow(italyItem); italyItem-> appendRow(romeItem); italyItem-> appendRow(veronaItem); // register the model treeView->setModel(standardModel); treeView->expandAll(); // selection changes shall trigger a slot QItemSelectionModel *selectionModel = treeView->selectionModel(); connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &MainWindow::selectionChangedSlot); }
視圖在單獨的選擇模型中管理選擇,可以使用() 方法檢索,檢索選擇模型是為了將一個槽連接到它的() 信號。
(文件來源:examples/widgets/tutorials/modelview/7_selections/mainwindow.cpp)
void MainWindow::selectionChangedSlot(const QItemSelection & /*newSelection*/, const QItemSelection & /*oldSelection*/) { // get the text of the selected item const QModelIndex index = treeView->selectionModel()->currentIndex(); QString selectedText = index.data(Qt::DisplayRole).toString(); // find out the hierarchy level of the selected item int hierarchyLevel = 1; QModelIndex seekRoot = index; while (seekRoot.parent().isValid()) { seekRoot = seekRoot.parent(); hierarchyLevel++; } QString showString = QString("%1, Level %2").arg(selectedText) .arg(hierarchyLevel); setWindowTitle(showString); }
通過調用()來獲得與選擇相對應的模型索引,并通過使用模型索引來獲得字段的字符串,然后只需計算該項的hierarchyLevel。頂級項沒有父項,()方法將返回一個默認構造的,這就是為什么使用parent()方法迭代到頂層,同時計算迭代期間執行的步驟。
選擇模型(如上所示)可以檢索,但也可以使用進行設置。這就是為什么有3個視圖類具有同步選擇,因為只使用了選擇模型的一個實例。要在3個視圖之間共享選擇模型,請使用() 并使用setSelectionModel()將結果分配給第二個和第三個視圖類。
使用模型/視圖的典型方法是封裝特定的數據,使其可用于視圖類。但是Qt也為公共底層數據結構提供了預定義的模型,如果其中一種可用的數據結構適合您的應用程序,那么預定義模型可能是一個不錯的選擇。
在迄今為止的所有示例中,數據在單元格中以文本或復選框的形式呈現,并以文本或復選框的形式進行編輯,提供這些表示和編輯服務的組件稱為delegate。一起來看一個名為Star Delegate的示例:
該視圖有一個setItemDelegate()方法,用于替換默認delegate并安裝自定義delegate。一個新的delegate可以通過創建一個繼承自QStyledItemDelegate的類來編寫,為了編寫一個顯示星號且沒有輸入功能的delegate并安裝自定義delegate。一個新的delegate,我們只需要重寫2個方法。
class StarDelegate : public QStyledItemDelegate { Q_OBJECT public: StarDelegate(QWidget *parent = nullptr); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; };
paint()根據底層數據的內容繪制星號,可以通過調用index.data()來查找數據。delegate的sizeHint()方法用于獲取每個星星的尺寸,因此單元格將提供足夠的高度和寬度來容納這些星星。
如果您想在視圖類的網格中使用自定義圖形表示方式顯示數據,那么編寫自定義delegates是正確的選擇。如果想要離開網格,不會使用自定義delegates,可以使用自定義視圖類。
模型的被動特性為程序員提供了新的挑戰,模型中的不一致可能導致應用程序崩潰。由于模型受到來自視圖的大量調用的影響,因此很難找出哪個調用使應用程序崩潰,以及哪個操作引入了問題。
Qt Labs提供了一種名為的軟件,可以在程序運行時檢查模型。每當模型被更改時,ModelTest都會掃描模型并使用斷言報告錯誤。這對于樹模型尤其重要,因為它們的層次性質為微妙的不一致留下了許多可能性。
與視圖類不同,ModelTest使用超出范圍的索引來測試模型。這意味著您的應用程序可能會在使用ModelTest時崩潰,即使沒有它它也可以完美地運行。因此在使用ModelTest時,您還需要處理所有超出范圍的索引。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:慧都網