Qt中的模型视图设计模式
文章目錄
- 1 初探Qt中的模型視圖設計模式
- 2 模型視圖中的索引
- 3 模型中的數據組織方式初探
1 初探Qt中的模型視圖設計模式
模型視圖設計模式的核心思想:
- 模型(數據)與視圖(顯示)相分離。
- 模型對外提供標準接口存取數據(不關心數據如何顯示)。
- 視圖自定義數據的顯示方式(不關心數據如何組織存儲)。
模型視圖模式的直觀理解:
模型視圖模式的工作機制:
- 當數據發生改變時:模型發出信號通知視圖。
- 當用戶與視圖進行交互時:視圖發出信號提供交互信息。
Qt中的模型類層次結構:
Qt中視圖類的層次結構:
關鍵技術問題:模型如何為數據提供統一的訪問方式?
深入理解:在Qt中,不管模型以什么結構組織數據,都必須為每一個數據提供獨一無二的索引;視圖通過索引訪問模型中的具體數據。
模型視圖編程示例:
Widget.h:
Widget.cpp:
#include "Widget.h" #include <QDir>Widget::Widget(QWidget *parent): QWidget(parent) {m_treeView.setParent(this);m_treeView.move(10, 10);m_treeView.resize(500, 300);m_fsModel.setRootPath(QDir::currentPath());m_treeView.setModel(&m_fsModel);m_treeView.setRootIndex(m_fsModel.index(QDir::currentPath())); }Widget::~Widget() {}main.cpp:
#include <QtGui/QApplication> #include "Widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }對模型視圖設計模式總結一下:
- 模型定義標準接口(成員函數)對數據進行訪問。
- 視圖通過標準接口獲取數據并定義顯示方式。
- 模型使用信號與槽的機制通知視圖數據變化。
- 模型的數據都是以層次結構表示的。
2 模型視圖中的索引
模型中的索引:
- 模型索引是數據與視圖分離的重要機制。
- 模型中的數據使用唯一的索引來訪問。
- 索引是訪問模型中具體數據的約定方式。
- QModelIndex是Qt中的模型索引類:
- 包含具體數據的訪問途徑。
- 包含一個指向模型的指針。
索引的意義:
索引中的行和列:
- 線性模型可以使用(row,column)作為數據索引。
問題:只用行和列描述數據索引是否足夠通用?
思考:
- 如何索引以屬性結構組織的數據?
模型中的通用樹形結構:
模型中數據索引的通用方式:
- 三元組:(row、column、parent)。
- 索引在需要時由模型實時創建。
- 使用空索引作為父節點表示頂層數據元素。
- 特殊的模型可以自定義特殊的索引獲取方式。
編程實驗:數據索引深入理解
Widget.h:
#ifndef WIDGET_H #define WIDGET_H#include <QtGui/QWidget> #include <QPlainTextEdit> #include <QFileSystemModel>class Widget : public QWidget {Q_OBJECTQPlainTextEdit m_edit;QFileSystemModel m_fsm; protected slots:void onDirectoryLoaded(const QString& path); public:Widget(QWidget *parent = 0);~Widget(); };#endif // WIDGET_HWidget.cpp:
#include "Widget.h" #include <QDir> #include <QModelIndex> #include <QByteArray> #include <QBuffer> #include <QTextStream>Widget::Widget(QWidget *parent): QWidget(parent) {m_edit.setParent(this);m_edit.move(10, 10);m_edit.resize(500, 300);connect(&m_fsm, SIGNAL(directoryLoaded(QString)), this, SLOT(onDirectoryLoaded(QString)));m_fsm.setRootPath(QDir::currentPath()); }void Widget::onDirectoryLoaded(const QString& path) {QModelIndex root = m_fsm.index(path);QByteArray array;QBuffer buffer(&array);if( buffer.open(QIODevice::WriteOnly) ){QTextStream out(&buffer);out << m_fsm.isDir(root) << endl;out << m_fsm.data(root).toString() << endl;out << root.data().toString() << endl;out << &m_fsm << endl;out << root.model() << endl;out << m_fsm.filePath(root) << endl;out << m_fsm.fileName(root) << endl;out << endl;for(int i=0; i<m_fsm.rowCount(root); i++){QModelIndex ci = m_fsm.index(i, 0, root);out << ci.data().toString() << endl;}out.flush();buffer.close();}if( buffer.open(QIODevice::ReadOnly) ){QTextStream in(&buffer);m_edit.insertPlainText(in.readAll());buffer.close();} }Widget::~Widget() {}main.cpp:
#include <QtGui/QApplication> #include "Widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }后面需要解決一個問題:QFileSystemModel中是如何組織數據的?如何手動解析QFileSystemModel中的數據?
3 模型中的數據組織方式初探
問題:不同的視圖如何顯示同一個模型中的數據?
Qt中的標準模型定義:
MainWindow.h:
MainWindow.cpp:
#include "MainWindow.h" #include <QStandardItem>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {initStanderdModel();initTableModel();m_tableView.setModel(&m_standerdModel); } void MainWindow::initStanderdModel() {QStandardItem* root = m_standerdModel.invisibleRootItem();QStandardItem* itemA = new QStandardItem();QStandardItem* itemB = new QStandardItem();QStandardItem* itemC = new QStandardItem();itemA->setData("A");//只是往數據項里面放了數據,并沒有告訴如何顯示itemA->setData("Tip A");itemA->setData("Help A");itemB->setData("B");itemB->setData("Tip B");itemC->setData("C");itemC->setData("Tip B");itemC->setData("Help C");root->setChild(0, 0, itemA);//itemA、itemB、itemC都是new出來的,這里將數據項root->setChild(0, 1, itemB);//加入模型的同時也相當于指定了父組件,不會造成內存泄漏root->setChild(1, 0, itemC);} void MainWindow::initTableModel() {m_tableView.resize(300,100);m_tableView.move(10,10);m_tableView.setParent(this); } MainWindow::~MainWindow() {}main.cpp:
#include <QtGui/QApplication> #include "MainWindow.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.show();return a.exec(); }運行結果如下:
我們會發現結果無法正常顯示,為了使數據能夠正常顯示,我們需要引入數據角色的概念:
- 模型中的數據在視圖中的用途(顯示方式)可能不同。
- 模型必須為數據設置特定數據角色(數據屬性)。
- 數據角色用于提示視圖數據的作用。
- 數據角色是不同視圖以統一風格顯示數據的標準。
Qt中的數據角色定義:
數據角色的意義:
- 定義了數據在特定系統下的標準用途。
- 不同的視圖可以通過相同標準顯示數據。
注意:數據角色只是一個附加的屬性,這個屬性代表推薦的數據顯示方式。不同的視圖完全可以自由解析或者忽略數據的角色信息。
更改后的代碼如下:
Widget.h:
Widget.cpp:
#include "Widget.h" #include <QStandardItem>Widget::Widget(QWidget *parent): QWidget(parent, Qt::WindowContextHelpButtonHint) {initModel();initView();m_tableView.setModel(&m_model);m_listView.setModel(&m_model);m_treeView.setModel(&m_model); }void Widget::initModel() {QStandardItem* root = m_model.invisibleRootItem();QStandardItem* itemA = new QStandardItem();QStandardItem* itemB = new QStandardItem();QStandardItem* itemC = new QStandardItem();QStandardItem* itemChild = new QStandardItem();itemA->setData("A", Qt::DisplayRole);itemA->setData("Tip A", Qt::ToolTipRole);itemA->setData("Help A", Qt::WhatsThisRole);itemB->setData("B", Qt::DisplayRole);itemB->setData("Tip B", Qt::ToolTipRole);itemC->setData("C", Qt::DisplayRole);itemC->setData("Tip C", Qt::ToolTipRole);itemC->setData("Help C", Qt::WhatsThisRole);itemChild->setData("Child", Qt::DisplayRole);itemChild->setData("Tip Child", Qt::ToolTipRole);itemChild->setData("Help Child", Qt::WhatsThisRole);itemC->setChild(0, 0, itemChild);root->setChild(0, 0, itemA);root->setChild(0, 1, itemB);root->setChild(1, 0, itemC); }void Widget::initView() {m_tableView.setParent(this);m_tableView.move(10, 10);m_tableView.resize(300, 100);m_listView.setParent(this);m_listView.move(10, 120);m_listView.resize(300, 100);m_treeView.setParent(this);m_treeView.move(10, 230);m_treeView.resize(300, 100); }Widget::~Widget() {}main.cpp:
#include <QtGui/QApplication> #include "Widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }運行結果如下:
參考資料:
總結
以上是生活随笔為你收集整理的Qt中的模型视图设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 氢氧化钠与水反应是放热反应还是吸热反应(
- 下一篇: 互斥信号量的删除与状态查询