翻譯|使用教程|編輯:龔雪|2023-02-24 10:17:22.760|閱讀 234 次
概述:本教程將為大家介紹每個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@ke049m.cn
文章轉載自:慧都網