Qt学习: Model/View实现表格和统计图

来源:互联网 发布:excel数据等距分组 编辑:程序博客网 时间:2024/04/30 18:57

博主QQ:1356438802


一、简介

       Model/View结构使数据管理与相应的数据显示相互独立,并提供了一系列标准的函数接口和用于Model模块与View模块之间的通信。它从MVC演化而来,MVC由三种对象组成,Model是应用程序对象,View是它的屏幕表示,Controller定义了用户界面如何对用户输入进行响应。把MVC中的View和Controller合在一起,就形成了Model/View结构。

二、运行图

(1)为了灵活对用户的输入进行处理,引入了Delegate,Model、View、Delegate三个模块之间通过信号与槽机制实现,当自身的状态发生改变时会发出信号通知其他模块。它们间的关系如下图1所示。

       QAbstractItemModel是所有Model的基类,但一般不直接使用QAbstractItemModel,而是使用它的子类。Model模块本身并不存储数据,而是为View和Delegate访问数据提供标准的接口。

       View模块从Model中获得数据项显示给用户,Qt提供了一些常用的View模型,如QTreeView、QTableView和QListView。

       Delegate的基本接口在QAbstractItemDelegate类中定义,通过实现paint()和sizeHint()以达到渲染数据项的目的。

(2)程序运行图如下图2所示。


三、详解

1、表格中嵌入控件

利用Delegate的方式实现表格中嵌入各种不同控件的效果,控件在需要编辑数据项时才出现。

(1)插入日历编辑框QDateLineEdit

[cpp] view plain copy
  1. #ifndef DATEDELEGATE_H  
  2. #define DATEDELEGATE_H  
  3.   
  4. #include <QtGui>  
  5.   
  6. class DateDelegate : public QItemDelegate  
  7. {  
  8.     Q_OBJECT  
  9.   
  10. public:  
  11.     DateDelegate(QObject *parent = 0);  
  12.   
  13.     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,  
  14.                            const QModelIndex &index) const;  
  15.   
  16.     void setEditorData(QWidget *editor, const QModelIndex &index) const;  
  17.     void setModelData(QWidget *editor, QAbstractItemModel *model,  
  18.                        const QModelIndex &index) const;  
  19.   
  20.     void updateEditorGeometry(QWidget *editor,  
  21.          const QStyleOptionViewItem &option, const QModelIndex &index) const;  
  22. };  
  23.   
  24. #endif  
[cpp] view plain copy
  1. #include "datedelegate.h"  
  2.   
  3. DateDelegate::DateDelegate(QObject *parent)  
  4.     : QItemDelegate(parent)  
  5. {  
  6. }  
  7.   
  8. QWidget *DateDelegate::createEditor(QWidget *parent,  
  9.     const QStyleOptionViewItem &/* option */,  
  10.     const QModelIndex &/* index */const  
  11. {  
  12.     QDateTimeEdit *editor = new QDateTimeEdit(parent);  
  13.     editor->setDisplayFormat("yyyy-MM-dd");  
  14.     editor->setCalendarPopup(true);  
  15.     editor->installEventFilter(const_cast<DateDelegate*>(this));  
  16.   
  17.     return editor;  
  18. }  
  19.   
  20. void DateDelegate::setEditorData(QWidget *editor,  
  21.                                      const QModelIndex &index) const  
  22. {  
  23.     QString dateStr = index.model()->data(index).toString();  
  24.     QDate date = QDate::fromString(dateStr,Qt::ISODate);  
  25.   
  26.     QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor);  
  27.     edit->setDate(date);  
  28. }  
  29.   
  30. void DateDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,  
  31.                                     const QModelIndex &index) const  
  32. {  
  33.     QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor);  
  34.     QDate date = edit->date();  
  35.   
  36.     model->setData(index, QVariant(date.toString(Qt::ISODate)));  
  37. }  
  38.   
  39. void DateDelegate::updateEditorGeometry(QWidget *editor,  
  40.     const QStyleOptionViewItem &option, const QModelIndex &/* index */const  
  41. {  
  42.     editor->setGeometry(option.rect);  
  43. }  
       分析:DateDelegate继承QItemDelegate,一般需要重定义声明中的几个虚函数。createEditor()函数完成创建控件的工作;setEditorDate()设置控件显示的数据,把Model数据更新至Delegate,相当于初始化工作;setModelDate()把Delegate中对数据的更改更新至Model中;updateEditor()更析控件区的显示。

(2)插入下拉列表框QComboBox

[cpp] view plain copy
  1. #include "combodelegate.h"  
  2.   
  3. ComboDelegate::ComboDelegate(QObject *parent)  
  4.     : QItemDelegate(parent)  
  5. {  
  6. }  
  7.   
  8. QWidget *ComboDelegate::createEditor(QWidget *parent,  
  9.     const QStyleOptionViewItem &/* option */,  
  10.     const QModelIndex &/* index */const  
  11. {  
  12.     QComboBox *editor = new QComboBox(parent);  
  13.     editor->addItem(QString::fromLocal8Bit("工人"));  
  14.     editor->addItem(QString::fromLocal8Bit("农民"));  
  15.     editor->addItem(QString::fromLocal8Bit("医生"));  
  16.     editor->addItem(QString::fromLocal8Bit("律师"));  
  17.     editor->addItem(QString::fromLocal8Bit("军人"));  
  18.   
  19.     editor->installEventFilter(const_cast<ComboDelegate*>(this));  
  20.   
  21.     return editor;  
  22. }  
  23.   
  24. void ComboDelegate::setEditorData(QWidget *editor,  
  25.                                      const QModelIndex &index) const  
  26. {  
  27.     QString str = index.model()->data(index).toString();  
  28.       
  29.     QComboBox *box = static_cast<QComboBox*>(editor);  
  30.     int i = box->findText(str);  
  31.     box->setCurrentIndex(i);  
  32. }  
  33.   
  34. void ComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,  
  35.                                     const QModelIndex &index) const  
  36. {  
  37.     QComboBox *box = static_cast<QComboBox*>(editor);  
  38.     QString str = box->currentText();  
  39.   
  40.     model->setData(index, str);  
  41. }  
  42.   
  43. void ComboDelegate::updateEditorGeometry(QWidget *editor,  
  44.     const QStyleOptionViewItem &option, const QModelIndex &/* index */const  
  45. {  
  46.     editor->setGeometry(option.rect);  
  47. }  

(3)插入微调器QSpinBox

[cpp] view plain copy
  1. #include "spindelegate.h"  
  2.   
  3. SpinDelegate::SpinDelegate(QObject *parent)  
  4.     : QItemDelegate(parent)  
  5. {  
  6. }  
  7.   
  8. QWidget *SpinDelegate::createEditor(QWidget *parent,  
  9.     const QStyleOptionViewItem &/* option */,  
  10.     const QModelIndex &/* index */const  
  11. {  
  12.     QSpinBox *editor = new QSpinBox(parent);  
  13.     editor->setRange(1000,10000);      
  14.   
  15.     editor->installEventFilter(const_cast<SpinDelegate*>(this));  
  16.   
  17.     return editor;  
  18. }  
  19.   
  20. void SpinDelegate::setEditorData(QWidget *editor,  
  21.                                      const QModelIndex &index) const  
  22. {  
  23.     int value = index.model()->data(index).toInt();  
  24.       
  25.     QSpinBox *spin = static_cast<QSpinBox*>(editor);  
  26.       
  27.     spin->setValue(value);  
  28. }  
  29.   
  30. void SpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,  
  31.                                     const QModelIndex &index) const  
  32. {  
  33.     QSpinBox *spin = static_cast<QSpinBox*>(editor);  
  34.     int value = spin->value();  
  35.   
  36.     model->setData(index, value);  
  37. }  
  38.   
  39. void SpinDelegate::updateEditorGeometry(QWidget *editor,  
  40.     const QStyleOptionViewItem &option, const QModelIndex &/* index */const  
  41. {  
  42.     editor->setGeometry(option.rect);  
  43. }  

2、柱状统计图

自定义的View实现一个柱状统计图对TableModel的表格数据进行显示。
[cpp] view plain copy
  1. #ifndef HISTOGRAMVIEW_H  
  2. #define HISTOGRAMVIEW_H  
  3.   
  4. #include <QtGui>  
  5.   
  6. class HistogramView : public QAbstractItemView  
  7. {  
  8.     Q_OBJECT  
  9. public:  
  10.     HistogramView(QWidget *parent=0);  
  11.       
  12.     QRect visualRect(const QModelIndex &index)const;  
  13.     void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible);  
  14.     QModelIndex indexAt(const QPoint &point) const;      
  15.       
  16.     void paintEvent(QPaintEvent *);  
  17.     void mousePressEvent(QMouseEvent *);  
  18.   
  19.     void setSelectionModel(QItemSelectionModel * selectionModel);  
  20.     QRegion itemRegion(QModelIndex index);    
  21.       
  22. protected slots:  
  23.     void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);  
  24.     void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected );  
  25.       
  26. protected:  
  27.     QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,  
  28.                             Qt::KeyboardModifiers modifiers);  
  29.     int horizontalOffset() const;  
  30.     int verticalOffset() const;      
  31.     bool isIndexHidden(const QModelIndex &index) const;  
  32.     void setSelection ( const QRect&rect, QItemSelectionModel::SelectionFlags flags );  
  33.     QRegion visualRegionForSelection(const QItemSelection &selection) const;         
  34.       
  35. private:  
  36.     QItemSelectionModel *selections;   
  37.       
  38.     QList<QRegion> listRegionM;    
  39.     QList<QRegion> listRegionF;   
  40.     QList<QRegion> listRegionS;   
  41.       
  42. };  
  43.   
  44. #endif   
[cpp] view plain copy
  1. #include "histogramview.h"  
  2.   
  3. HistogramView::HistogramView(QWidget *parent)  
  4.     : QAbstractItemView(parent)  
  5. {}  
  6.   
  7. void HistogramView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)  
  8. {  
  9.     QAbstractItemView::dataChanged(topLeft, bottomRight);  
  10.       
  11.     viewport()->update();  
  12. }  
  13.   
  14. QRect HistogramView::visualRect(const QModelIndex &index) const  
  15. {}  
  16.   
  17. void HistogramView::scrollTo(const QModelIndex &index, ScrollHint hint)  
  18. {}  
  19.   
  20. QModelIndex HistogramView::indexAt(const QPoint &point) const  
  21. {  
  22.     QPoint newPoint(point.x(),point.y());  
  23.   
  24.     QRegion region;  
  25.     foreach(region,listRegionM)  
  26.     {  
  27.         if (region.contains(newPoint))  
  28.         {  
  29.             int row = listRegionM.indexOf(region);  
  30.             QModelIndex index = model()->index(row, 3,rootIndex());  
  31.             return index;  
  32.         }  
  33.     }  
  34.       
  35.     return QModelIndex();  
  36. }  
  37.   
  38. QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction,  
  39.                             Qt::KeyboardModifiers modifiers)  
  40. {}  
  41.                              
  42. int HistogramView::horizontalOffset() const  
  43. {  
  44. }  
  45.   
  46. int HistogramView::verticalOffset() const  
  47. {}  
  48.   
  49. bool HistogramView::isIndexHidden(const QModelIndex &index) const  
  50. {}  
  51.   
  52. void HistogramView::setSelectionModel(QItemSelectionModel * selectionModel)  
  53. {  
  54.     selections = selectionModel;  
  55. }  
  56.   
  57. void HistogramView::mousePressEvent(QMouseEvent *e)  
  58. {  
  59.     QAbstractItemView::mousePressEvent(e);  
  60.     setSelection(QRect(e->pos().x(),e->pos().y(),1,1),QItemSelectionModel::SelectCurrent);      
  61. }  
  62.       
  63. QRegion HistogramView::itemRegion(QModelIndex index)  
  64. {  
  65.     QRegion region;  
  66.   
  67.     if (index.column() == 3)  
  68.         region = listRegionM[index.row()];  
  69.   
  70.     return region;  
  71. }  
  72.   
  73. void HistogramView::setSelection ( const QRect &rect, QItemSelectionModel::SelectionFlags flags )  
  74. {  
  75.      int rows = model()->rowCount(rootIndex());  
  76.      int columns = model()->columnCount(rootIndex());  
  77.      QModelIndex selectedIndex;  
  78.   
  79.      for (int row = 0; row < rows; ++row)   
  80.      {  
  81.          for (int column = 1; column < columns; ++column)   
  82.          {  
  83.              QModelIndex index = model()->index(row, column, rootIndex());  
  84.              QRegion region = itemRegion(index);  
  85.            
  86.              if (!region.intersected(rect).isEmpty())  
  87.              selectedIndex = index;  
  88.          }  
  89.      }  
  90.        
  91.      if(selectedIndex.isValid())   
  92.          selections->select(selectedIndex,flags);  
  93.      else   
  94.      {  
  95.          QModelIndex noIndex;  
  96.          selections->select(noIndex, flags);  
  97.      }  
  98. }  
  99.   
  100. QRegion HistogramView::visualRegionForSelection(const QItemSelection &selection) const  
  101. {}  
  102.   
  103. void HistogramView::selectionChanged(const QItemSelection & selected, const QItemSelection & deselected )  
  104. {  
  105.     viewport()->update();  
  106. }  
  107.   
  108. void HistogramView::paintEvent(QPaintEvent *)  
  109. {  
  110.     QPainter painter(viewport());  
  111.   
  112.     painter.setPen(Qt::black);  
  113.     int x0 = 40;  
  114.     int y0 = 250;  
  115.       
  116.     // draw coordinate    
  117.     painter.drawLine(x0, y0, 40, 30);  
  118.     painter.drawLine(38, 32, 40, 30);  
  119.     painter.drawLine(40, 30, 42, 32);  
  120.     painter.drawText(5, 45, tr("income"));  
  121.       
  122.     for (int i=1; i<5; i++) {  
  123.         painter.drawLine(-1,-i*50,1,-i*50);  
  124.         painter.drawText(-20,-i*50,tr("%1").arg(i*5));  
  125.     }  
  126.   
  127.     // x轴  
  128.     painter.drawLine(x0, y0, 540, 250);  
  129.     painter.drawLine(538, 248, 540, 250);  
  130.     painter.drawLine(540, 250, 538, 252);  
  131.     painter.drawText(500, 270, tr("name"));  
  132.     int row;  
  133.     // name  
  134.     int posD = x0+20;  
  135.     for (row = 0; row < model()->rowCount(rootIndex()); row++)   
  136.     {  
  137.         QModelIndex index = model()->index(row, 0, rootIndex());  
  138.         QString dep = model()->data(index).toString();      
  139.           
  140.         painter.drawText(posD,y0+20,dep);  
  141.         posD += 50;  
  142.     }  
  143.     // income  
  144.     int posM = x0+20;  
  145.     for (row = 0; row < model()->rowCount(rootIndex()); row++)  
  146.     {  
  147.         QModelIndex index = model()->index(row, 3, rootIndex());  
  148.         int income = model()->data(index).toDouble();  
  149.   
  150.         int width = 10;  
  151.   
  152.         if (selections->isSelected(index))  
  153.             painter.setBrush(QBrush(Qt::darkBlue,Qt::SolidPattern));  
  154.         else  
  155.             painter.setBrush(Qt::blue);  
  156.   
  157.         painter.drawRect(QRectF(posM + 10, y0-income/25, width, income/25));  
  158.         QRegion regionM(posM + 10, y0-income/25, width, income/25);  
  159.         listRegionM << regionM;  
  160.   
  161.         posM += 50;  
  162.     }  
  163. }  
       分析:对父类的QAbstractItemView中的所有纯虚函数都必须进行声明,纯虚函数包括visualRect()、scrollTo()、indexAt()、moveCursor()、horizontalOffset()、verticalOffset()、isIndexHidden()、setSelection()和visualRegionForSelection(),这些函数并不一定都要实现,根据功能要求选择实现。

四、总结

(1)Mode/View结构比较难于理解,在此先作简单的介绍,以后再进行更加深入的研究。

(2)感兴趣的可以下载源码分析,并在其基础上进行自己的开发,本人水平有限,也只能提供代码供读者延伸。

(3)源码已经打包上传到csdn上可登录下载(http://download.csdn.net/detail/taiyang1987912/7797583)。  

(4)若有更好的设计建议,也可发邮件沟通,在此先感谢!邮箱地址yang.ao@i-soft.com.cn。


0 0