日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt中模型/视图结构

發布時間:2023/12/29 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt中模型/视图结构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
8.1 概述
MVC設計模式是起源于Smalltalk的一種與用戶界面相關的設計模式。通過使用此模型,可以有效地分離數據和用戶界面。MVC設計模式包括三個元素:表示數據的模型 (Model)、表示用戶界面的視圖(View)和定義了用戶在界面上的操作控制(Controller)。 與MVC設計模式類似,Qt引入了模型/視圖結構用于完成數據與界面的分離,即InterView框架。但不同的是,Qt的InterView框架中把視圖和控制部件結合在一起,使得? 框架更為簡潔。為了靈活地處理用戶輸入,InterView框架引入了代理(Delegate)。通過使用代理,能夠自定義數據條目(item)的顯示和編輯方式。 Qt的模型/視圖結構分為了三種部分:模式(Model)、視圖(View)和代理(Delegate)。其中,模型與數據通信,并為了其它部件提供接口;而視圖從模型中獲得用來 引用數據條目的模型索引(Model Index)。在視圖中,代理負責繪制數據條目,當編輯條目時,代理和模型直接進行通信。模型/視圖/代理之間通過信號和槽進行通信。 它們之間的關系如下: 數據發生改變時,模型發出信號通知視圖。 用戶對界面進行操作,視圖發生信號。 代理發出信號告知模型和視圖編輯器目前的狀態。


基本概念 1、模型(Model) InterView框架中的所有模型都基于抽象基類QAbstractItemModel類,此類由QProxyModel、QAbstractListModel、QAbstractTableModel、QAbstractProxyModel、 QDirModel、QFileSystemModel、QHelpContentModel?和?QStandardItemModel類繼承。 2、視圖(View) InterView框架中的所有視圖都基于抽象基類QAbstractItemView類,此類由QColumnView、QHeaderView、QListView、QTableView和QTreeView類繼承。 3、代理(Delegate) InterView框架中的所有代理都基于抽象基類QAbstractItemDelegate類,此類由QItemDelegate?和?QStyledItemDelegate類繼承。
運行效果


main.cpp
#include "mainwindow.h" #include <QAbstractItemModel> #include <QAbstractItemView> #include <QItemSelectionModel> #include <QApplication> #include <QDirModel> #include <QTreeView> #include <QListView> #include <QTableView> #include <QSplitter> /* * 新建一個QDirModel對象,對數據訪問做準備,QDirModel的創建還可以設置過濾器,即只有符合條件的文件或目錄才能被訪問 * QDirModel類繼承自QAbstractItemModel類,為訪問本地文件系統提供數據模型,它提供了新建、刪除、創建目錄等一系列與 * 文件操作相關的函數,此處只是用來顯示本地文件系統 * * 新建三種不同的View對象,以便文件目錄可以以三種不同的方式顯示 * * tree.setModel(&model):調用setModel()函數設置View對象的Model為QDirModel對象的model。 * * tree.setSelectionMode (QAbstractItemView::MultiSelection):設置QTreeView對象的選擇方式為多選 * *list.setSelectionModel (tree.selectionModel ()):設置QListView對象與QTreeView對象使用相同的選擇類型 * * 為了實現雙擊QTreeView對象中的某個目錄時,QListView對象和QTableView對象中顯示此選定目錄下的所有文件和目錄, * 需要鏈接QTreeView對象的doubleClicked()信號與QListView對象和QTableView對象的setRootIndex()槽函數 */ int main(int argc, char *argv[]) { QApplication a(argc, argv); QDirModel model; QTreeView tree; QListView list; QTableView table; tree.setModel (&model); list.setModel (&model); table.setModel (&model); tree.setSelectionMode (QAbstractItemView::MultiSelection); list.setSelectionModel (tree.selectionModel ()); table.setSelectionModel (tree.selectionModel ()); QObject::connect (&tree, SIGNAL(doubleClicked(QModelIndex)), &list, SLOT(setRootIndex(QModelIndex))); QObject::connect (&tree, SIGNAL(doubleClicked(QModelIndex)), &table, SLOT(setRootIndex(QModelIndex))); QSplitter *spliter = new QSplitter; spliter->addWidget (&tree); spliter->addWidget (&list); spliter->addWidget (&table); spliter->setWindowTitle (QObject::tr ("Model/View")); spliter->show(); return a.exec(); }
8.2 模型(Model) 實現自定義模型可以通過QAbstractItemModel類繼承,也可以通過QAbstractListModel和QAbstractTableModel類繼承實現列表模型或表格模型。在數值代碼保存,然后 通過外鍵關聯操作來查找其真實的含義,這一方法為了避免冗余。
Item主要角色及其描述
常量 描述
Qt::DisplayRole 顯示文字
Qt::DecorationRole 繪制裝飾數據(通常是圖標)
Qt::EditRole 在編輯器中編輯的數據
Qt::ToolTipRole 工具提示
Qt::StatusTipRole 狀態欄提示
Qt::WhatsThisRole What's This文字
Qt::SizeHintRole 尺寸提示
Qt::FontRole 默認代理的繪制使用的字體
Qt::TextAlignmentRole 默認代理的對齊方式
Qt::BackgroundRole 默認代理的背景畫刷
Qt::ForegroundRole 默認代理的前景畫刷
Qt::CheckStateRole 默認代理的檢查框狀態
Qt::UserRole 用戶自定義的數據的起始位置

運行畫面


modelex.h
#ifndef MODELEX_H #define MODELEX_H #include <QAbstractTableModel> #include <QMap> #include <QVector> #include <QStringList> /* * QMap<Key,T>提供了一個從類型為Key的鍵到類型為T的值的映射。 * rowCount()、columnCount()、data()和返回表頭數據的headerData()函數 * 是QAbstractTableModel類的純數函數 * * 純虛函數是一種特殊的虛函數,在許多情況下,在基類中不能對虛函數給出有意義的實現, * 而把它聲明為純虛函數,它的實現留給該基類的派生類去做。這就是純虛函數的作用 */ class ModelEx : public QAbstractTableModel { public: explicit ModelEx(QObject *parent = 0); virtual int rowCount (const QModelIndex &parent) const; virtual int columnCount (const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData (int section, Qt::Orientation orientation, int role) const; signals: public slots: private: QVector<short> army; //定義一個短型軍種類型容器 QVector<short> weaponType; //定義一個短型武器類型容器 QMap<short, QString> armyMap; //定義一個從short類型的鍵值到類型QString的值得映射 QMap<short, QString> weaponTypeMap; //定義一個從short類型的鍵值到類型QString的值得映射 QStringList weapon; //定義一個字符串武器鏈表 QStringList header; //定義一個頭結點鏈表 void populateModel(); //完成表格數據的初始化填充 }; #endif // MODELEX_H
modelex.cpp
#include "modelex.h" ModelEx::ModelEx(QObject *parent) : QAbstractTableModel(parent) { armyMap[1] = tr("空軍"); armyMap[2] = tr("海軍"); armyMap[3] = tr("陸軍"); armyMap[4] = tr("海軍陸戰隊"); weaponTypeMap[1] = tr("轟炸機"); weaponTypeMap[2] = tr("航空母艦"); weaponTypeMap[3] = tr("直升機"); weaponTypeMap[4] = tr("兩棲攻擊艦"); weaponTypeMap[5] = tr("驅逐艦"); weaponTypeMap[6] = tr("兩棲戰艦"); weaponTypeMap[7] = tr("坦克"); weaponTypeMap[8] = tr("戰斗機"); populateModel (); } void ModelEx::populateModel () { header << tr("軍種") << tr("種類") << tr("武器"); army << 1 << 2 << 3 << 4 << 4 << 2 << 3 << 1; weaponType << 1 << 2 << 3 << 4 <<5 << 6 << 7 << 8; weapon << tr("B-2") << tr("尼米茲級") << tr("阿帕奇") << tr("黃蜂級") << tr("阿利伯克級") << tr("AAAV") << tr("MIAI") << ("F-22"); } /* * 返回行 */ int ModelEx::rowCount (const QModelIndex &parent) const { return army.size (); } /* * 返回列 */ int ModelEx::columnCount (const QModelIndex &parent) const { return 3; } /* * QVariant類類似于C++的聯合(union)數據類型,它不僅能夠保存很多Qt類型的值,包括QColor、QBrush、QFont、 * QPen、QRect、QString和QSize等,也能夠存放容器類的值。 * data()函數返回指定索引的數據,即將數值映射為文字 */ QVariant ModelEx::data (const QModelIndex &index, int role) const { if(!index.isValid ()) { return QVariant(); } /*Qt::DisplayRole用來存取視圖中顯示的文字*/ if(role == Qt::DisplayRole) { switch(index.column ()) { case 0: return armyMap[army[index.row ()]]; break; case 1: return weaponTypeMap[weaponType[index.row ()]]; break; case 2: return weapon[index.row ()]; break; default: return QVariant(); break; } } return QVariant(); } /* * headerData()函數返回固定的表頭數據,設置水平表頭的標題 */ QVariant ModelEx::headerData (int section, Qt::Orientation orientation, int role) const { if(role == Qt::DisplayRole && orientation == Qt::Horizontal) return header[section]; return QAbstractTableModel::headerData (section, orientation, role); }
main.cpp
#include <QApplication> #include "modelex.h" #include <QTableView> int main(int argc, char *argv[]) { QApplication a(argc, argv); ModelEx modelEx; QTableView view; view.setModel(&modelEx); view.setWindowTitle(QObject::tr("modelEx")); view.resize(400,400); view.show(); return a.exec(); }
8.3 視圖(View) 實現自定義的View,可繼承自QAbstractItemView類,對所需的純虛函數進行重定義與實現,對于QAbstractItemView類中的純虛函數,在子類中必須進行重定義, 但不一定要實現,可根據需要選擇實現。
顯示結果


mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QStandardItemModel> #include <QTableView> #include <QMenuBar> #include <QMenu> #include <QAction> #include <QSplitter> #include "histogramview.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); void createAction(); void createMenu(); void setupModel(); void setupView(); void openFile(QString); private: QMenu *fileMenu; QAction *openAct; QStandardItemModel *model; QTableView *table; QSplitter *splitter; HistogramView *histogram; public slots: void slotOpen(); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include <QFileDialog> #include <QFile> #include <QTextStream> #include <QStringList> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { createAction (); createMenu (); setupModel (); setupView (); setWindowTitle (tr("View Example")); resize(600, 660); } MainWindow::~MainWindow() { } void MainWindow::createAction () { openAct = new QAction(tr("打開"), this); connect (openAct, SIGNAL(triggered(bool)), this, SLOT(slotOpen())); } /* * 創建一個文件菜單欄 * 將openAct動作插入到這個菜單欄里 */ void MainWindow::createMenu () { fileMenu = new QMenu(tr("文件"), this); fileMenu->addAction(openAct); menuBar ()->addMenu (fileMenu); } void MainWindow::setupModel () { model = new QStandardItemModel(4, 4, this); model->setHeaderData (0, Qt::Horizontal, tr("部門")); model->setHeaderData (1, Qt::Horizontal, tr("男")); model->setHeaderData (2, Qt::Horizontal, tr("女")); model->setHeaderData (3, Qt::Horizontal, tr("退休")); } void MainWindow::setupView () { splitter = new QSplitter; splitter->setOrientation (Qt::Vertical); histogram = new HistogramView(splitter); histogram->setModel (model); table = new QTableView; //新建一個QTableView對象 table->setModel (model); //為QTableView對象設置相同的Model /*新建一個QItemSelectModel對象作為QTableView對象使用的選擇模型*/ QItemSelectionModel *selectionModel = new QItemSelectionModel(model); table->setSelectionModel (selectionModel); histogram->setSelectionModel (selectionModel); splitter->addWidget (table); splitter->addWidget (histogram); setCentralWidget (splitter); connect (selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), table, SLOT(selectionChanged(QItemSelection,QItemSelection))); connect (selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), histogram, SLOT(selectionChanged(QItemSelection,QItemSelection))); } /* * 打開一個*.txt文件 * 如果文件非空讀取文件信息 */ void MainWindow::slotOpen () { QString name; name = QFileDialog::getOpenFileName (this, "打開", ".", "histogram files(*.txt)"); if(!name.isEmpty ()) { openFile (name); } } /* * 一行行讀取*.txt文件內容,當遇到“,”分割數據 * QFile類提供了一個接口,用于讀取或寫入文件 * QTextStream類可以方便地讀取單詞、行和數字。 * 在循環中一次讀取文件中的一行數據,然后插入到表格對應的一行數據中 */ void MainWindow::openFile (QString path) { if(!path.isEmpty ()) { QFile file(path); if(file.open (QFile::ReadOnly | QFile::Text)) { QTextStream stream(&file); QString line; /*從文本中移除一行的數據*/ model->removeRows (0, model->rowCount (QModelIndex()), QModelIndex()); int row = 0; do { line = stream.readLine (); if(!line.isEmpty ()) { /*設置一行插入多個數據,一次插入一個數據*/ model->insertRows (row, 1, QModelIndex()); QStringList pieces = line.split (",", QString::SkipEmptyParts); /*將數據設置到row行、0、1、2、3列*/ model->setData (model->index (row, 0, QModelIndex()), pieces.value (0)); model->setData (model->index (row, 1, QModelIndex()), pieces.value (1)); model->setData (model->index (row, 2, QModelIndex()), pieces.value (2)); model->setData (model->index (row, 3, QModelIndex()), pieces.value (3)); row++; } }while(!line.isEmpty ()); file.close (); } } }
histogramview.h
#ifndef HISTOGRAMVIEW_H #define HISTOGRAMVIEW_H #include <QAbstractItemView> #include <QItemSelection> #include <QRegion> #include <QMouseEvent> /* * visualRect (),scrollTo (),indexAt (),moveCursor (),horizontalOffset (),verticalOffset () * isIndexHidden (),setSelection ()和visualRegionForSelection ():QAbstractItemView類中的純虛函數 * 這些純虛函數不一定要實現,可以根據需要選擇性地實現,但一定要聲明。 * * QModelIndex indexAt(const QPoint &point) const:當鼠標在視圖中單擊或位置發生改變時被觸動,它返回鼠標所 * 在點的QModelIndex值。當鼠標處在某一個數據項的區域中,則返回此數據項的Index值,否則返回一個空的Index。 * * void mousePressEvent (QMouseEvent *event):柱狀統計圖可以被鼠標單擊選擇,選中后以不同的方式顯示。 * * selectionChanged (const QItemSelection &selected, const QItemSelection &deselected):當數據項 * 選擇發生變化時,此槽函數將響應。 * * void dataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight):當模型中的數據發生 * 變更時,此槽函數將響應。 * * void setSelection (const QRect &rect, QItemSelectionModel::SelectionFlags flags):將位于QRect內 * 的數據項按照SelectionFlags(描述被選擇的數據項以何種方式進行更新)指定的方式進行更新。QItemSelectModel類提供 * 多種可用的SelecttionFlags,常用的有QItemSelectModel::Select、QItemSelectModel::Current類。 * * QItemSelectionModel *selections:用于保存與視圖選擇項相關的內容。 * * QList <QRegion> MRegionList:用于保存其中某一類型柱狀圖的區域范圍,而每個區域是QList中的一個值。 */ class HistogramView : public QAbstractItemView { public: HistogramView(QWidget *parent = 0); QRect visualRect (const QModelIndex &index) const; void scrollTo (const QModelIndex &index, ScrollHint hint=EnsureVisible); QModelIndex indexAt(const QPoint &point) const; //為selecttions賦初值 void setSelectionModel (QItemSelectionModel *selectionModel); QRegion itemRegion(QModelIndex index); void paintEvent (QPaintEvent *); void mousePressEvent (QMouseEvent *event); protected slots: void selectionChanged (const QItemSelection &selected, const QItemSelection &deselected); void dataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight); protected: QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,Qt::KeyboardModifiers modifiers); int horizontalOffset () const; int verticalOffset () const; bool isIndexHidden (const QModelIndex &index) const; void setSelection (const QRect &rect, QItemSelectionModel::SelectionFlags flags); QRegion visualRegionForSelection (const QItemSelection &selection) const; private: QItemSelectionModel *selections; QList <QRegion> MRegionList; QList <QRegion> FRegionList; QList <QRegion> SRegionList; }; #endif // HISTOGRAMVIEW_H

histogramview.cpp
#include "histogramview.h" #include <QPainter> HistogramView::HistogramView(QWidget *parent) :QAbstractItemView(parent) { } //paintEvent()函數具體完成柱狀統計圖繪制的工作 void HistogramView::paintEvent (QPaintEvent *) { QPainter painter(viewport ()); //將viewport()作為繪圖設備新建一個QPainter對象 painter.setPen (Qt::black); int x0 = 40; int y0 = 280; //繪制y軸坐標 painter.drawLine (x0, y0, 40, 18); painter.drawLine (36, 22, 40, 18); painter.drawLine (44, 22, 40, 18); painter.drawText (27, 15, tr("人數")); for(int i = 0; i <= 5; i++) { painter.drawLine (40, 280 - (5 - i) * 50, 42, 280 - (5 - i) * 50); painter.drawText (25, 285 - (5 - i) * 50, tr("%1").arg ((5 - i) * 5)); } //繪制x軸坐標 painter.drawLine (x0, y0, 562, 280); painter.drawLine (558, 276, 562, 280); painter.drawLine (558, 284, 562, 280); painter.drawText (567, 285, tr("部門")); // for(int i = 0; i <= 9; i++) // { // painter.drawLine (490 - (8 - i) * 50, 280, 490 - (8 - i) * 50, 278); // painter.drawText (487 - (8 - i) * 50, 295, tr("%1").arg (i + 1)); // } int posD = x0 + 20; int row; //讀取文件中每一行的第一例數據 for(row = 0; row < model()->rowCount (rootIndex ()); ++row) { QModelIndex index = model()->index (row, 0, rootIndex ()); QString dep = model ()->data (index).toString (); painter.drawText (posD, y0 + 15, dep); posD += 50; } /*完成了表格第1列數據的柱狀統計圖的繪制*/ //男 int posM = x0 + 20; for(row = 0; row < model()->rowCount (rootIndex ()); row++) { QModelIndex index=model()->index(row,1,rootIndex()); int male=model()->data(index).toDouble(); int width = 10; //使用不同畫刷顏色區別選中與未選中的數據項 if(selections->isSelected(index)) painter.setBrush(QBrush(Qt::blue,Qt::Dense3Pattern)); else painter.setBrush(Qt::blue); //繪制長方形條x,y,w,h painter.drawRect(QRect(posM, y0 - male * 10, width, male * 10)); QRegion regionM(posM, y0 - male * 10, width, male * 10); //將此數據所占據的區域保存到MRegionList列表中,為后面的數據項選擇做準備。 MRegionList << regionM; posM += 50; } /*完成了表格第2列數據的柱狀統計圖的繪制*/ //女條目框 int posF = x0 + 30; for(row = 0; row < model()->rowCount (rootIndex ()); ++row) { QModelIndex index = model()->index (row, 2, rootIndex ()); int female = model()->data (index).toDouble (); int width = 10; if(selections->isSelected (index)) painter.setBrush (QBrush(Qt::red, Qt::Dense3Pattern)); else painter.setBrush (Qt::red); //繪制長方形x,y,w,h painter.drawRect (QRect(posF, y0 - female * 10, width, female * 10)); QRegion regionF(posF, y0 - female * 10, width, female * 10); //將此數據所占據的區域保存到FRegionList列表中,為后面的數據項選擇做準備。 FRegionList << regionF; posF += 50; } /*完成了表格第3列數據的柱狀統計圖的繪制*/ //退休條目框 int posS = x0 + 40; for(row = 0; row < model()->rowCount (rootIndex ()); ++row) { QModelIndex index = model ()->index (row, 3, rootIndex ()); int retire = model()->data (index).toDouble (); int width = 10; if(selections->isSelected (index)) painter.setBrush (QBrush(Qt::green, Qt::Dense3Pattern)); else painter.setBrush (Qt::green); //繪制長方形x,y,w,h painter.drawRect (QRect(posS, y0 - retire * 10, width, retire * 10)); QRegion regionS(posS, y0 - retire * 10, width, retire * 10); SRegionList << regionS; posS += 50; } } /* * dataChanged()函數實現當Model中的數據改變時,調用繪圖設備的update()函數進行更新,反應數據的變化 */ void HistogramView::dataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight) { QAbstractItemView::dataChanged (topLeft, bottomRight); viewport ()->update (); } /* * 設置選擇模式,至此View已經能正確顯示表格的統計數據,而且對表格中的某個數據項進行修改時能夠及時顯示將變化反應在柱狀統計圖中 */ void HistogramView::setSelectionModel (QItemSelectionModel *selectionModel) { selections = selectionModel; } /* * 完成當數據項發生變化時調用update()函數,重繪繪圖設備即可工作。此函數是將其他View中的操作引起的數據項選擇變化放映到自身 * View的顯示中。 */ void HistogramView::selectionChanged (const QItemSelection &selected, const QItemSelection &deselected) { viewport ()->update (); } /* * 在調用setSelection()函數確定鼠標單擊點是否在某個數據項的區域內,并設置選擇項 */ void HistogramView::mousePressEvent (QMouseEvent *event) { QAbstractItemView::mousePressEvent (event); setSelection (QRect(event->pos().x (), event->pos().y (), 1, 1), QItemSelectionModel::SelectCurrent); } /* * QModelIndex selectIndex:用于保存被選中的數據項的Index值。此處只實現用鼠標單擊選擇,而沒有實現鼠標拖曳框選,因此,鼠標 * 動作只可能選中一個數據項。 * * for循環里面:確定在rect中是否含有數據項。此處采用遍歷的方式將每個數據項的區域與rect區域進行intersected操作,獲得兩者之間的 * 交集。若此交集不為空則說明此數據項被選中,將它的Index值賦給selectIndex。 * * QRegion region = itemRegion (index):返回指定index的數據項所占用的區域 * * 完成select()函數的調用,即完成最后對選擇項的設置工作。select()函數時在實現setSelection()函數的調用,即完成最后對選擇項的 * 設置。select()函數是在實現setSelection()函數時必須調用的。 */ void HistogramView::setSelection (const QRect &rect, QItemSelectionModel::SelectionFlags flags) { int rows = model()->rowCount (rootIndex ()); //獲得總行數 int columns = model()->columnCount (rootIndex()); //獲得總列數 QModelIndex selectedIndex; for(int row = 0; row < rows; ++row) { for(int column = 1; column < columns; ++column) { QModelIndex index = model()->index (row, column, rootIndex ()); QRegion region = itemRegion (index); if(!region.intersected (rect).isEmpty ()) selectedIndex = index; } } if(selectedIndex.isValid ()) selections->select (selectedIndex, flags); else { QModelIndex noIndex; selections->select (noIndex, flags); } } QModelIndex HistogramView::indexAt (const QPoint &point) const { QPoint newPoint(point.x (), point.y ()); QRegion region; //男列 foreach(region, MRegionList) { if(region.contains (newPoint)) { int row = MRegionList.indexOf (region); QModelIndex index = model()->index (row, 1, rootIndex ()); return index; } } //女列 foreach (region, FRegionList) { if(region.contains (newPoint)) { int row = FRegionList.indexOf (region); QModelIndex index = model ()->index (row, 2, rootIndex ()); return index; } } //合計列 foreach(region, SRegionList) { if(region.contains (newPoint)) { int row = SRegionList.indexOf (region); QModelIndex index = model()->index (row, 3, rootIndex ()); return index; } } return QModelIndex(); } QRegion HistogramView::itemRegion (QModelIndex index) { QRegion region; if(index.column () == 1) //男 region = MRegionList[index.row ()]; if(index.column () == 2) //女 region = FRegionList[index.row ()]; if(index.column () == 3) region = SRegionList[index.row ()]; return region; } QRect HistogramView::visualRect(const QModelIndex &index)const{} void HistogramView::scrollTo(const QModelIndex &index,ScrollHint){} QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers){} int HistogramView::horizontalOffset()const{} int HistogramView::verticalOffset()const{} bool HistogramView::isIndexHidden(const QModelIndex &index)const{} QRegion HistogramView::visualRegionForSelection(const QItemSelection &selection)const{}
8.4代理(Dlegate) 在表格中嵌入各種不同控件,通過表格中的控件對編輯的內容進行限定。通常情況下,這種在表格中插入空間的方式,空間始終顯示。在表格中控件數目較多時,將 影響表格的美觀。此時,可利用Delegate的方式實現同樣的效果,控件只有在需要編輯數據項時才會顯示,從而解決了上述所遇到的問題。 運行效果如下:

main.cpp
#include "mainwindow.h" #include <QApplication> #include <QStandardItemModel> #include <QFile> #include <QTextStream> #include <QTableView> #include "datedelegate.h" #include "combodelegate.h" #include "spindelegate.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); /*定義一個4*4的表格對象*/ QStandardItemModel model(4, 4); QTableView tableView; tableView.setModel (&model); DateDelegate dateDelegate; tableView.setItemDelegateForColumn (1, &dateDelegate); ComboDelegate comboDelegate; tableView.setItemDelegateForColumn (2, &comboDelegate); SpinDelegate spinDelegate; tableView.setItemDelegateForColumn (3, &spinDelegate); model.setHeaderData (0, Qt::Horizontal, QObject::tr("姓名")); model.setHeaderData (1, Qt::Horizontal, QObject::tr ("生日")); model.setHeaderData (2, Qt::Horizontal, QObject::tr("職業")); model.setHeaderData (3, Qt::Horizontal, QObject::tr("收入")); QFile file("test.txt"); if(file.open (QFile::ReadOnly | QFile::Text)) { QTextStream stream(&file); QString line; model.removeRows (0, model.rowCount (QModelIndex()), QModelIndex()); int row = 0; do{ line = stream.readLine (); if(!line.isEmpty ()) { /*一次插入一行數據,每次插入一個數據*/ model.insertRows (row, 1, QModelIndex()); /*當遇到”,“跳過該項,將數據插入pieces鏈表中*/ QStringList pieces = line.split (",", QString::SkipEmptyParts); model.setData (model.index (row, 0, QModelIndex()), pieces.value(0)); model.setData (model.index (row, 1, QModelIndex()), pieces.value (1)); model.setData (model.index (row, 2, QModelIndex()), pieces.value (2)); model.setData (model.index (row, 3, QModelIndex()), pieces.value (3)); row++; } }while(!line.isEmpty ()); file.close (); } tableView.setWindowTitle (QObject::tr ("Delegate")); tableView.resize (450, 250); tableView.show(); return a.exec(); }
combodelegate.h
#ifndef COMBODELEGATE_H #define COMBODELEGATE_H #include <QItemDelegate> #include <QWidget> class ComboDelegate : public QItemDelegate { public: ComboDelegate(QObject *parent = 0); QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData (QWidget *editor, const QModelIndex &index) const; void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry (QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; #endif // COMBODELEGATE_H

combodelegate.cpp
#include "combodelegate.h" #include <QComboBox> ComboDelegate::ComboDelegate(QObject *parent) : QItemDelegate(parent) { } /* * createEditor()函數中創建了一個QComboBox控件,并插入可現實的條目,安裝事件過濾器。 */ QWidget *ComboDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QComboBox *editor = new QComboBox(parent); editor->addItem (tr("工人")); editor->addItem (tr("農民")); editor->addItem (tr("醫生")); editor->addItem (tr("律師")); editor->addItem (tr("軍人")); editor->installEventFilter (const_cast<ComboDelegate*>(this)); return editor; } /* * 更新代理控件中的數據顯示 */ void ComboDelegate::setEditorData (QWidget *editor, const QModelIndex &index) const { QString str = index.model ()->data (index).toString (); QComboBox *box = static_cast<QComboBox*>(editor); int i = box->findText (str); box->setCurrentIndex (i); } /* * 更新model中的數據 */ void ComboDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *box = static_cast<QComboBox*>(editor); QString str = box->currentText (); model->setData (index, str); } void ComboDelegate::updateEditorGeometry (QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry (option.rect); }
datedelegate.h
#ifndef DATEDELEGATE_H #define DATEDELEGATE_H #include <QItemDelegate> #include <QWidget> class DateDelegate : public QItemDelegate { public: DateDelegate(QObject *parent = 0); QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData (QWidget *editor, const QModelIndex &index) const; void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry (QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; #endif // DATEDELEGATE_H

datedelegate.cpp
#include "datedelegate.h" #include <QDateTimeEdit> DateDelegate::DateDelegate(QObject *parent) : QItemDelegate(parent) { } /* * 完成創建控件的工作,創建由參數中的QModelIndex對象指定的表項數據的編輯控件,并對控件的內容進行設定 * * 新建一個QDateTimeEdit對象作為編輯時的輸入控件 * 設置此QDateTimeEdit對象的顯示格式為yyyy-MM-dd,此為ISO標準顯示方式 * 設置日歷選擇的顯示以Popup的方式,即下拉菜單的方式顯示 * 調用QObject類的installEventFilter()函數安裝事件過濾器,使DateDelegate能夠捕獲QDateTimeEdit對象的事件 */ QWidget *DateDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QDateTimeEdit *editor = new QDateTimeEdit(parent); editor->setDisplayFormat ("yyyy-MM-dd"); editor->setCalendarPopup (true); editor->installEventFilter (const_cast<DateDelegate*>(this)); return editor; } /* * QString dataStr = index.model ()->data (index).toString (): 獲取指定index數據項的數據,調用QModelIndex的 * model()函數可獲得提供index的Model對象,data()函數返回的是一個QVariant對象,toString()函數將它轉換為一個QString類型數據 * * 通過QDate的fromString()函數將以QString類型表示的日期數據轉換為QDate類型。Qt::ISODate表示QDate類型的日期是以ISO格式 * 保存的,這樣最終轉換得的QDate數據也是ISO格式,使控件顯示與表格顯示保持一致。 * * QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor):將editor裝換為QDateTimeEdit對象,以獲得編輯控件的 * 對象指針。 */ void DateDelegate::setEditorData (QWidget *editor, const QModelIndex &index) const { QString dataStr = index.model ()->data (index).toString (); QDate date = QDate::fromString (dataStr, Qt::ISODate); QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor); edit->setDate (date); } /* * static_cast<QDateTimeEdit*>(editor):通過緊縮轉換獲得編輯控件的對象指針 * QDate date = edit->date ():獲得編輯控件中的數據更新 * model->setData (index, QVariant(date.toString (Qt::ISODate))): 調用setData()函數 * 將數據修改更新到Model中。 * */ void DateDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor); QDate date = edit->date (); model->setData (index, QVariant(date.toString (Qt::ISODate))); } void DateDelegate::updateEditorGeometry (QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry (option.rect); }
spindelegate.h
#ifndef SPINDELEGATE_H #define SPINDELEGATE_H #include <QItemDelegate> class SpinDelegate : public QItemDelegate { public: SpinDelegate(QObject *parent = 0); QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData (QWidget *editor, const QModelIndex &index) const; void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry (QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; #endif // SPINDELEGATE_H

spindelegate.cpp
#include "spindelegate.h" #include <QSpinBox> SpinDelegate::SpinDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget *SpinDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QSpinBox *editor = new QSpinBox(parent); editor->setRange (0, 10000); editor->installEventFilter (const_cast<SpinDelegate*>(this)); return editor; } void SpinDelegate::setEditorData (QWidget *editor, const QModelIndex &index) const { int value = index.model ()->data (index).toInt (); QSpinBox *box = static_cast<QSpinBox*>(editor); box->setValue (value); } void SpinDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QSpinBox *box = static_cast<QSpinBox*>(editor); int value = box->value (); model->setData (index, value); } void SpinDelegate::updateEditorGeometry (QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry (option.rect); }

總結

以上是生活随笔為你收集整理的Qt中模型/视图结构的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。