38.Qt模型/视图结构

  • 1.模型/视图类
  • 2.模型
  • 3.视图
  • 4.代理

 

 

1  模型/视图类

  InterView框架提供了一些可以直接使用的模型类和视图类,如QStandardModel类,QDirModel类,QStringListModel类,以及QColumnView类,QHeaderView类,QListView类,QTableView类和QTreeView类

 

简单目录浏览器:

 1 #include "mainwindow.h"
 2 #include <QApplication>
 3 
 4 #include <QAbstractItemModel>
 5 #include <QAbstractItemView>
 6 #include <QItemSelectionModel>
 7 
 8 #include <QDirModel>
 9 #include <QTreeView>
10 #include <QListView>
11 #include <QTableView>
12 #include <QSplitter>
13 
14 int main(int argc, char *argv[])
15 {
16     QApplication a(argc, argv);
17 //    MainWindow w
18 //    w.show();
19 
20     //新建一个QDirModel对象,为数据访问做准备,QDirModel的创建还可以设置过滤器
21     //即只有符合条件的文件或目录才可被访问
22     //QDirModel类继承自QAbstractItemModel类,为访问本地系统提供数据模型,它提供了如
23     //新建,删除,创建目录等一系列与文件操作相关的函数
24     QDirModel model;
25 
26     //新建三种不同的View对象,以便文件目录可以以三种不同的方式显示
27     QTreeView tree;
28     QListView list;
29     QTableView table;
30 
31     //设置View对象的Model为QDirModel对象的model
32     tree.setModel(&model);
33     list.setModel(&model);
34     table.setModel(&model);
35 
36     //设置QTreeView对象的选择方式为多选
37     //QAbstractItemView提供了五种选择模式,QAbstractItem View::SingleSelection.
38     //QAbstractItemView::NoSelection,QAbstractItemView::ContiguousSelection
39     //QAbstractItemView::ExtendedSelection和QAbstractItemView::MultiSelection
40     tree.setSelectionMode(QAbstractItemView::MultiSelection);
41     //设置QTableView对象与QTreeView对象使用相同的选择模型
42     list.setSelectionModel(tree.selectionModel());
43     table.setSelectionMode(tree.selectionMode());
44 
45     //为了实现双击QTreeView对象中的某个目录时,QListView对象和QTableView对象显示此选定目录
46     //下的所有文件和目录,需要连接QTreeView对象的doubleClicked()信号与QListView对象的
47     //setRootIndex()槽函数
48     QObject::connect(&tree,SIGNAL(doubleClicked(QModelIndex)),&list,
49                      SLOT(setRootIndex(QModelIndex)));
50     QObject::connect(&tree,SIGNAL(doubleClicked(QModelIndex)),&table,
51                      SLOT(setRootIndex(QModelIndex)));
52 
53     QSplitter *splitter = new QSplitter;
54     splitter->addWidget(&tree);
55     splitter->addWidget(&list);
56     splitter->addWidget(&table);
57     splitter->setWindowTitle(QObject::tr("Model/view"));
58     splitter->show();
59 
60     return a.exec();
61 }

2  模型

  实现自定义模型可以通过QAbstractItemModel类继承,也可以通过QAbstractListModel和QAbstractTableModel类继承实现列表模型或表格模型;

代码示例:

  • modelx.h
     1 #ifndef MODELEX_H
     2 #define MODELEX_H
     3 
     4 #include <QAbstractTableModel>
     5 #include <QVector>
     6 #include <QMap>
     7 #include <QStringList>
     8 #include <QObject>
     9 
    10 class modelex:public QAbstractTableModel
    11 {
    12 public:
    13     explicit modelex(QObject *parent=0);
    14 
    15     virtual int rowCount(const QModelIndex &parent=QModelIndex()) const;
    16     virtual int columnCount(const QModelIndex &parent=QModelIndex()) const;
    17 
    18     QVariant data(const QModelIndex &index, int role) const;
    19     //返回表头的函数
    20     QVariant headerData(int section,Qt::Orientation orientation,int role)const;
    21 
    22 private:
    23     QVector<short> army;
    24     QVector<short> weaponType;
    25 
    26     //数值-文字映射
    27     QMap<short,QString> armyMap;
    28     QMap<short,QString> weaponTypeMap;
    29 
    30     QStringList weapon;
    31     QStringList header;
    32 
    33     //完成表格数据的初始化填充
    34     void populateModel();
    35 };
    36 
    37 #endif // MODELEX_H

     

  • modelx.cpp
      1 #include "modelex.h"
      2 #include "modelex.h"
      3 modelex::modelex(QObject *parent):
      4     QAbstractTableModel(parent)
      5 {
      6     //创建映射
      7     armyMap[1]=tr("空军");
      8     armyMap[2]=tr("海军");
      9     armyMap[3]=tr("陆军");
     10     armyMap[4]=tr("海军陆战队");
     11 
     12     weaponTypeMap[1]=tr("轰炸机");
     13     weaponTypeMap[2]=tr("战斗机");
     14     weaponTypeMap[3]=tr("航空母舰");
     15     weaponTypeMap[4]=tr("驱逐舰");
     16     weaponTypeMap[5]=tr("直升机");
     17     weaponTypeMap[6]=tr("坦克");
     18     weaponTypeMap[7]=tr("两栖攻击舰");
     19     weaponTypeMap[8]=tr("两栖战车");
     20 
     21     //绘制模型
     22     populateModel();
     23 }
     24 
     25 
     26 
     27 //获取模型的行数
     28 int modelex::rowCount(const QModelIndex &parent) const
     29 {
     30     return army.size();
     31 }
     32 
     33 //返回模型的列数
     34 int modelex::columnCount(const QModelIndex &parent) const
     35 {
     36     return 4;
     37 }
     38 
     39 //返回指定索引的数据,即将数值映射为文字
     40 //循环把模型的每行每列给绘制了(函数名不能换成其他名字)
     41 QVariant modelex::data(const QModelIndex &index, int role) const
     42 {
     43     if(!index.isValid())
     44     {
     45         return QVariant();
     46     }
     47 
     48     //模型中的条目可以有不同个角色,这样就可以在不同的情况下提供不同的数据.
     49     //如,Qt::DisplayRole用来存取视图中显示的文字,角色由枚举类Qt::ItemDataRole定义
     50     //Qt::DisplayRole   显示文字
     51     //Qt::DecorationRole   绘制装饰数据(通常是图标)
     52     //Qt::EditRole   在编辑器中编辑的数据
     53     //Qt::ToolTipRole   工具提示
     54     //Qt::StatusTipRole   状态栏提示
     55     //Qt::WhatsThisRole   What's This文字
     56     //Qt::SizeHintRole   尺寸提示
     57     //Qt::FontRole   默认代理的绘制使用的字体
     58     //Qt::TextAlignmentRole   默认代理的对齐方式
     59     //Qt::BackgroundRole   默认代理的背景画刷
     60     //Qt::ForegroundRole   默认代理的前景画刷
     61     //Qt::CheckStateRole   默认代理的检查框状态
     62     //Qt::UserRole   用户自定义的数据的起始位置
     63     if(role==Qt::DisplayRole)
     64     {
     65         //遍历没一列
     66         switch(index.column())
     67         {
     68         case 0:
     69             //当前行数对应的军队
     70             return armyMap[army[index.row()]];
     71             break;
     72         case 1:
     73             //当前行数对应的类型,以及此类型对应的武器种类
     74             return weaponTypeMap[weaponType[index.row()]];
     75         case 2:
     76             //当前行数对应的武器
     77             return weapon[  index.row()  ];
     78         default:
     79             return QVariant();
     80         }
     81     }
     82     return QVariant();
     83 }
     84 
     85 //返回固定的表头数据,设置水平表头的标题(内部循环实现)
     86 QVariant modelex::headerData(int section, Qt::Orientation orientation, int role) const
     87 {
     88     if(role==Qt::DisplayRole&&orientation==Qt::Horizontal)
     89         return header[section];
     90 
     91     return QAbstractTableModel::headerData(section,orientation,role);
     92 }
     93 
     94 //绘制
     95 void modelex::populateModel()
     96 {
     97     //表头
     98     header<<tr("军种")<<tr("武器种类")<<tr("武器")<<tr("测试");
     99     //军队
    100     army<<1<<2<<3<<4<<2<<4<<3<<1;
    101     //武器种类
    102     weaponType<<1<<3<<5<<7<<4<<8<<6<<3;
    103     //武器
    104     weapon<<tr("B-2")<<tr("尼米兹级")<<tr("黄蜂级")<<tr("阿利伯克级")
    105          <<tr("阿帕奇")<<tr("AAAV")<<tr("M1A1")<<tr("F-22");
    106 }

     

  • main.cpp
     1 #include <QApplication>
     2 
     3 #include "modelex.h"
     4 #include <QTableView>
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     QApplication a(argc, argv);
     9 
    10     modelex modleEx;
    11     QTableView view;
    12     view.setModel(&modleEx);
    13     view.setWindowTitle(QObject::tr("模型示例"));
    14     view.resize(400,400);
    15     view.show();
    16     return a.exec();
    17 }

     


     

3  视图

   实现自定义的View,可继承自QAbstractItemView类,对所需的纯虚函数进行重定义与实现,对于QAbstractItemView类中的纯虚函数,在子类必须进行重定义,但不一定要实现,可根据需要选择实现.

  • histogramview.h
     1 #ifndef HISTOGRAMVIEW_H
     2 #define HISTOGRAMVIEW_H
     3 #include <QAbstractItemView>
     4 #include <QItemSelectionModel>
     5 #include <QRegion>
     6 #include <QMouseEvent>
     7 
     8 
     9 
    10 class HistogramView : public QAbstractItemView
    11 {
    12 public:
    13     HistogramView(QWidget *parent);
    14 
    15     //14-17 一定要声明
    16     QRect visualRect(const QModelIndex &index) const;
    17     void scrollTo(const QModelIndex &index, ScrollHint hint=EnsureVisible);
    18     //当鼠标处在某个数据项的区域中,则返回此数据项的Index值,否则返回一个空的Index
    19     QModelIndex indexAt(const QPoint &point) const;
    20 
    21 
    22     //为selections赋初值
    23     void setSelectionModel(QItemSelectionModel *selectionModel);
    24     QRegion itemRegion(QModelIndex index);
    25 
    26     //完成柱状统计图的绘制
    27     void paintEvent(QPaintEvent *);
    28     //柱状统计图可以被鼠标单击选择,选中后以不同的方式显示
    29     void mousePressEvent(QMouseEvent *event);
    30 
    31 protected slots:
    32     //当数据项选择发生变化时此槽函数将响应
    33     void selectionChanged(const QItemSelection &selected,
    34                           const QItemSelection &deselected);
    35     //当模型中的数据发生变更时,此槽函数将响应
    36     void dataChanged(const QModelIndex &topLeft,
    37                      const QModelIndex &bottomRight);
    38 
    39 protected:
    40     //39-48 一定要声明
    41     QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
    42     int horizontalOffset() const;
    43     int verticalOffset() const;
    44     bool isIndexHidden(const QModelIndex &index) const;
    45     //将位于QRect内的数据项按照SelectionFlags(描述被选择的数据项以何种方式进行更新)
    46     //指定的方式进行更新.QItemSelectionModel类提供多种可用的SelectionFlags,常用的有
    47     //QItemSelectionModel::Select,QItemSelectionModel::Current等
    48     void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags);
    49     QRegion visualRegionForSelection(const QItemSelection &selection) const;
    50 
    51 private:
    52     //用于保存与视图选项相关的内容
    53     QItemSelectionModel *selections;
    54     //用于保存其中某一类型柱状图区域范围,而每个区域是QList中的一个值
    55     QList<QRegion> MRegionList;
    56     QList<QRegion> FRegionList;
    57     QList<QRegion> SRegionList;
    58 
    59 
    60 };
    61 
    62 #endif // HISTOGRAMVIEW_H

     

  • histogramview.cpp
      1 #include "histogramview.h"
      2 
      3 #include <QPainter>
      4 
      5 
      6 //当鼠标处在某个数据项的区域中,则返回此数据项的Index值,否则返回一个空的Index
      7 QModelIndex HistogramView::indexAt(const QPoint &point) const
      8 {
      9     QPoint newPoint(point.x(),point.y());
     10     QRegion region;
     11     //检查当前点是否处于第一列(男)数据的区域中
     12     foreach(region,MRegionList)//男列
     13     {
     14         if(region.contains(newPoint))
     15         {
     16             int row = MRegionList.indexOf(region);
     17             QModelIndex index = model()->index(row,1,rootIndex());
     18             return index;
     19         }
     20     }
     21 
     22     //检查当前点是否处于第二列(女)数据的区域中
     23     foreach(region,FRegionList)//女列
     24     {
     25         if(region.contains(newPoint))
     26         {
     27             int row = FRegionList.indexOf(region);
     28             QModelIndex index = model()->index(row,2,rootIndex());
     29             return index;
     30         }
     31     }
     32 
     33     //检查当前点是否处于第三列(合计)数据的区域中
     34     foreach(region,SRegionList) //合计 列
     35     {
     36         if(region.contains(newPoint))
     37         {
     38             int row=SRegionList.indexOf(region);
     39             QModelIndex index = model()->index(row,3,rootIndex());
     40             return index;
     41         }
     42     }
     43     return QModelIndex();
     44 }
     45 
     46 //为selections赋初值
     47 void HistogramView::setSelectionModel(QItemSelectionModel *selectionModel)
     48 {
     49     selections=selectionModel;
     50 }
     51 
     52 
     53 QRegion HistogramView::itemRegion(QModelIndex index)
     54 {
     55     QRegion region;
     56     if(index.column()==1) //
     57         region = MRegionList[index.row()];
     58     if(index.column()==2) //
     59         region = FRegionList[index.row()];
     60     if(index.column()==3) //退休
     61         region = SRegionList[index.row()];
     62 
     63     return region;
     64 }
     65 
     66 //完成柱状统计图的绘制
     67 void HistogramView::paintEvent(QPaintEvent *)
     68 {
     69     //以viewport()作为绘图设备新建一个QPainter对象
     70     QPainter painter(viewport());
     71     painter.setPen(Qt::black);
     72 
     73     int x0=40;
     74     int y0=250;
     75 
     76     //20-46行完成了x,y坐标轴的绘制,并标注坐标轴的变量
     77     //y坐标轴
     78     painter.drawLine(x0,y0,40,30);
     79     //箭头绘制
     80     painter.drawLine(38,32,40,30);
     81     painter.drawLine(40,30,42,32);
     82 
     83     painter.drawText(20,30,tr("人数"));
     84     //绘制坐标
     85     for(int i=0;i<5;i++)
     86     {
     87         painter.drawLine(1,i*50,1,i*50);
     88         painter.drawText(20,i*50,tr("%1").arg((5-i)*5));
     89     }
     90     //x坐标轴
     91     painter.drawLine(x0,y0,540,250);
     92     painter.drawLine(538,248,540,250);
     93     painter.drawLine(540,250,538,252);
     94     painter.drawText(545,250,tr("部门"));
     95 
     96     int posD=x0+20;
     97     int row;
     98     //遍历模式的行数
     99     for(row=0;row<model()->rowCount(rootIndex());row++)
    100     {
    101         //获得第0列
    102         QModelIndex index = model()->index(row,0,rootIndex());
    103         QString dep=model()->data(index).toString();
    104 
    105         painter.drawText(posD,y0+20,dep);
    106         posD += 50;
    107     }
    108 
    109 
    110     //50-75 完成第一列数据的柱状统计图的绘制
    111     //
    112     int posM=x0+20;
    113     for(row=0;row<model()->rowCount(rootIndex());row++)
    114     {
    115         //获得第一列
    116         QModelIndex index=model()->index(row,1,rootIndex());
    117         int male = model()->data(index).toDouble();
    118 
    119         int width = 10;
    120         //使用不同画刷颜色区别选择与未被选择的数据项
    121         if(selections->isSelected(index))
    122         {
    123             painter.setBrush(QBrush(Qt::blue,Qt::Dense3Pattern));
    124         }
    125         else
    126         {
    127             painter.setBrush(Qt::blue);
    128         }
    129 
    130         //根据当前数据项的值按比例绘制一个方形表示此数据项
    131         painter.drawRect(QRect(posM,y0-male*10,width,male*10));
    132         QRegion regionM(posM,y0-male*10,width,male*10);
    133         //将此数据所占据的区域保存到MRegionList列表中,为后面的数据项选择做准备
    134         MRegionList<<regionM;
    135         posM+=50;
    136     }
    137 
    138     //77-100    完成表格第二列数据的柱状统计图的绘制,同样,使用不同的画刷颜色区别
    139     //选中与未被选中的数据项,同时保存每个数据所占的区域至FRegionList列表中.
    140     //
    141     int posF=x0+30;
    142     for(row=0;row<model()->rowCount(rootIndex());row++)
    143     {
    144         QModelIndex index=model()->index(row,2,rootIndex());
    145         int female = model()->data(index).toDouble();
    146 
    147         int width = 10;
    148         if(selections->isSelected(index))
    149         {
    150             painter.setBrush(QBrush(Qt::red,Qt::Dense3Pattern));
    151         }
    152         else
    153         {
    154             painter.setBrush(Qt::red);
    155         }
    156 
    157         //左上角坐标,宽,长度
    158         painter.drawRect(QRect(posF,y0-female*10,width,female*10));
    159         //把区域添加到FRegionList
    160         QRegion regionM(posF,y0-female*10,width,female*10);
    161         FRegionList<<regionM;
    162         posF+=50;
    163     }
    164 
    165     //102-125    完成表格第三列数据的柱状统计图的绘制,同样,使用不同的画刷颜色区别
    166     //选中与未被选中的数据项,同时保存每个数据所占的区域至FRegionList列表中.
    167     //退休
    168     int posS=x0+40;
    169     for(row=0;row<model()->rowCount(rootIndex());row++)
    170     {
    171         QModelIndex index=model()->index(row,3,rootIndex());
    172         int retire = model()->data(index).toDouble();
    173 
    174         int width = 10;
    175         if(selections->isSelected(index))
    176         {
    177             painter.setBrush(QBrush(Qt::green,Qt::Dense3Pattern));
    178         }
    179         else
    180         {
    181             painter.setBrush(Qt::green);
    182         }
    183 
    184         painter.drawRect(QRect(posS,y0-retire*10,width,retire*10));
    185         QRegion regionS(posS,y0-retire*10,width,retire*10);
    186         SRegionList<<regionS;
    187         posS+=50;
    188     }
    189 }
    190 
    191 //柱状统计图可以被鼠标单击选择,选中后以不同的方式显示
    192 //在调用setSelection()函数时确定鼠标单击点是否在某个数据项的区域内,并设置选择项
    193 void HistogramView::mousePressEvent(QMouseEvent *event)
    194 {
    195     QAbstractItemView::mousePressEvent(event);
    196     setSelection(QRect(event->pos().x(),event->pos().y(),1,1),
    197                  QItemSelectionModel::SelectCurrent);
    198 }
    199 
    200 //当数据项变化时调用update()函数,重绘绘图设备,此函数是将其他View中的操作引起的数据项选择变化反映到自身View的显示中
    201 void HistogramView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
    202 {
    203     viewport()->update();
    204 }
    205 
    206 //当model中的数据更改时,调用绘图设备的update()函数进行更新,反映数据段的变化
    207 void HistogramView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
    208 {
    209     QAbstractItemView::dataChanged(topLeft,bottomRight);
    210     viewport()->update();
    211 }
    212 
    213 
    214 //将位于QRect内的数据项按照SelectionFlags(描述被选择的数据项以何种方式进行更新)
    215 //指定的方式进行更新.QItemSelectionModel类提供多种可用的SelectionFlags,常用的有
    216 //QItemSelectionModel::Select,QItemSelectionModel::Current等
    217 void HistogramView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags)
    218 {
    219     //获取总行数
    220     int rows = model()->rowCount(rootIndex());
    221     //获取总列数
    222     int columns = model()->columnCount(rootIndex());
    223     //用于保存被选中的数据项的Index值.此处只实现鼠标单击选择,而
    224     //没有实现鼠标拖拽框选,因此,鼠标动作只可能选中一个数据项.
    225     //若实现框选,则可使用QModelIndexList来保存所有被选中的数据项的Index值
    226     QModelIndex selectedIndex;
    227 
    228     //确定在rect中是否含有数据项.此处采用遍历的方式将每个数据项的区域与rect区域进行intersected操作
    229     //获得两者之间的交集.若此交集不为空则说明此数据项被选中,将它的Index赋值给selectedIndex
    230     for(int row=0;row<rows;++row)
    231     {
    232         for(int column=1;column<columns;++column)
    233         {
    234             QModelIndex index=model()->index(row,column,rootIndex());
    235             QRegion region = itemRegion(index);
    236 
    237             if(!region.intersected(rect).isEmpty())
    238             {
    239                 selectedIndex = index;
    240             }
    241         }
    242         if(selectedIndex.isValid())
    243         {
    244             //select()函数时在实现setSelection()函数时必须调用的
    245             selections->select(selectedIndex,flags);
    246         }
    247         else
    248         {
    249             QModelIndex noIndex;
    250             selections->select(noIndex,flags);
    251         }
    252     }
    253 }
    254 
    255 QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
    256 {
    257 
    258 }
    259 
    260 int HistogramView::horizontalOffset() const
    261 {
    262 
    263 }
    264 
    265 int HistogramView::verticalOffset() const
    266 {
    267 
    268 }
    269 
    270 bool HistogramView::isIndexHidden(const QModelIndex &index) const
    271 {
    272 
    273 }
    274 
    275 QRegion HistogramView::visualRegionForSelection(const QItemSelection &selection) const
    276 {
    277 
    278 }
    279 
    280 HistogramView::HistogramView(QWidget *parent)
    281         :QAbstractItemView(parent)
    282 {
    283 
    284 }
    285 
    286 QRect HistogramView::visualRect(const QModelIndex &index) const
    287 {
    288 
    289 }
    290 
    291 void HistogramView::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint)
    292 {
    293 
    294 }

     

  • mainwindow.h
     1 #ifndef MAINWINDOW_H
     2 #define MAINWINDOW_H
     3 
     4 #include <QMainWindow>
     5 
     6 #include <QStandardItemModel>
     7 #include <QTableView>
     8 #include <QMenuBar>
     9 #include <QMenu>
    10 #include <QAction>
    11 #include <QSplitter>
    12 
    13 #include "histogramview.h"
    14 
    15 namespace Ui {
    16 class MainWindow;
    17 }
    18 
    19 class MainWindow : public QMainWindow
    20 {
    21     Q_OBJECT
    22 
    23 public:
    24     explicit MainWindow(QWidget *parent = 0);
    25     ~MainWindow();
    26     void createAction();
    27     void createMenu();
    28     void setupModel();
    29     void setupView();
    30 
    31 public:
    32     void openFile(QString);
    33 
    34 public slots:
    35     void slotOpen();
    36 
    37 
    38 private:
    39     Ui::MainWindow *ui;
    40 
    41     QMenu *fileMenu;
    42     QAction *openAct;
    43 
    44     QStandardItemModel *model;
    45     QTableView *table;
    46     QSplitter *splitter;
    47 
    48 private:
    49     HistogramView *histogram;
    50 };
    51 
    52 #endif // MAINWINDOW_H

     

  • mainwindow.cpp
      1 #include "mainwindow.h"
      2 #include "ui_mainwindow.h"
      3 
      4 #include <QFileDialog>
      5 #include <QFile>
      6 #include <QTextStream>
      7 #include <QStringList>
      8 
      9 
     10 
     11 MainWindow::MainWindow(QWidget *parent) :
     12     QMainWindow(parent),
     13     ui(new Ui::MainWindow)
     14 {
     15     ui->setupUi(this);
     16     //创建菜单项
     17     createAction();
     18     //创建菜单
     19     createMenu();
     20     //创建模型
     21     setupModel();
     22     //创建视图
     23     setupView();
     24 
     25     setWindowTitle(tr("View Example"));
     26     resize(600,600);
     27 
     28 }
     29 
     30 MainWindow::~MainWindow()
     31 {
     32     delete ui;
     33 }
     34 
     35 //创建菜单选项
     36 void MainWindow::createAction()
     37 {
     38     openAct = new QAction(tr("打开"),this);
     39 
     40     connect(openAct,SIGNAL(triggered(bool)),this,SLOT(slotOpen()));
     41 }
     42 
     43 
     44 //创建菜单
     45 void MainWindow::createMenu()
     46 {
     47     fileMenu=new QMenu(tr("文件"),this);
     48     fileMenu->addAction(openAct);
     49     menuBar()->addMenu(fileMenu);
     50 }
     51 
     52 //新建一个Model并设置表头数据
     53 void MainWindow::setupModel()
     54 {
     55     //创建模型4行4列
     56     model = new QStandardItemModel(4,4,this);
     57     model->setHeaderData(0,Qt::Horizontal,tr("部门"));
     58     model->setHeaderData(1,Qt::Horizontal,tr(""));
     59     model->setHeaderData(2,Qt::Horizontal,tr(""));
     60     model->setHeaderData(3,Qt::Horizontal,tr("退休"));
     61 
     62 
     63 }
     64 
     65 //创建视图
     66 void MainWindow::setupView()
     67 {
     68     //分割窗口
     69     splitter = new QSplitter;
     70     splitter->setOrientation(Qt::Vertical);
     71 
     72     //新建一个HistogramView对象,在splitter中绘制
     73     histogram = new HistogramView(splitter);
     74 
     75     //为HistogramView对象设置相同的Model
     76     histogram->setModel(model);
     77     //创建表格视图
     78     table = new QTableView;
     79     //为QTableView对象设置相同的Model
     80     table->setModel(model);
     81 
     82     //新建一个QItemSelectionModel对象作为QTableView对象使用的选择模型
     83     //使选择table可以在柱状图上面显示
     84     QItemSelectionModel *selectionModel=new QItemSelectionModel(model);
     85     table->setSelectionModel(selectionModel);
     86     histogram->setSelectionModel(selectionModel);
     87 
     88     //添加table和histogram
     89     splitter->addWidget(table);
     90     splitter->addWidget(histogram);
     91 
     92 
     93     //设置中心控件
     94     setCentralWidget(splitter);
     95 
     96     //连接选择模型的selectionChanged()信号与HistogramView对象的SelectionChanged()槽函数,以便使
     97     //QTableView对象中的选择变化能够反映到table和自定义的HistogramView对象的显示中
     98     connect(selectionModel,SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
     99             table,SLOT(selectionChanged(QItemSelection,QItemSelection)));
    100     connect(selectionModel,SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
    101             histogram,SLOT(selectionChanged(QItemSelection,QItemSelection)));
    102 }
    103 
    104 //打开文件并读取
    105 void MainWindow::openFile(QString path)
    106 {
    107     //读文件
    108     if(!path.isEmpty())
    109     {
    110         //根据路径打开文件
    111         QFile file(path);
    112         //以只读文本方式打开
    113         if(file.open(QFile::ReadOnly | QFile::Text))
    114         {
    115             //创建文件流
    116             QTextStream stream(&file);
    117             //保存读取的每一行
    118             QString line;
    119 
    120             //移除当前所有的行
    121             model->removeRows(0,model->rowCount(QModelIndex()),
    122                               QModelIndex());
    123             int row = 0;
    124             do
    125             {
    126                 //依次读取每一行
    127                 line = stream.readLine();
    128                 //如果读取的不为空
    129                 if(!line.isEmpty())
    130                 {
    131                     //插入一行数据
    132                     model->insertRows(row,1,QModelIndex());
    133                     //根据逗号拆分成很多部分
    134                     QStringList pieces = line.split(",",QString::SkipEmptyParts);
    135                     //分别填充第row行,0,1,2,3列
    136                     model->setData(model->index(row,0,QModelIndex()),
    137                                    pieces.value(0));
    138                     model->setData(model->index(row,1,QModelIndex()),
    139                                    pieces.value(1));
    140                     model->setData(model->index(row,2,QModelIndex()),
    141                                    pieces.value(2));
    142                     model->setData(model->index(row,3,QModelIndex()),
    143                                    pieces.value(3));
    144                     row++;
    145                 }
    146 
    147             }while(!line.isEmpty());
    148             file.close();
    149         }
    150     }
    151 }
    152 
    153 //与打开菜单项相对应的槽函数
    154 void MainWindow::slotOpen()
    155 {
    156     QString name;
    157     name = QFileDialog::getOpenFileName(this,"打开",".","histogram files(*.txt)");
    158     if(!name.isEmpty())
    159     {
    160         openFile(name);
    161     }
    162 }

     

  • main.cpp
     1 #include "mainwindow.h"
     2 #include <QApplication>
     3 
     4 int main(int argc, char *argv[])
     5 {
     6     QApplication a(argc, argv);
     7     MainWindow w;
     8     w.show();
     9 
    10     return a.exec();
    11 }

     

4  代理

  在表格中嵌入各种不同控件,通过表格中的控件对编辑的内容进行限定.通常情况下,这种在表格中插入控件的方式,控件始终显示.当表格中控件数据较多时,将影响表格的美观.此时,可以利用Delegate的方式实现同样的效果,控件只有在需要编辑数据项的时候才会显示,从而解决了上述问题.

运行效果

  • datadelegate.h
     1 #ifndef DATADELEGATE_H
     2 #define DATADELEGATE_H
     3 
     4 #include <QItemDelegate>
     5 
     6 class DataDelegate : public QItemDelegate
     7 {
     8     Q_OBJECT
     9 
    10 public:
    11     DataDelegate(QObject *parent=0);
    12     //完成创建控件的工作,创建由参数中的QModelIndex对象指定的表项数据的编辑控件
    13     //并对控件的内容进行限定
    14     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    15     //设置控件显示的数据,将Model中的数据更新至Delegate中,相当于一个初始化工作
    16     void setEditorData(QWidget *editor,const QModelIndex &index) const;
    17     //将Deletate中对数据的改变更新至Model中
    18     void setModelData(QWidget *editor,QAbstractItemModel *model,const QModelIndex &index) const;
    19     //更新控件区的显示
    20     void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex &index) const;
    21 };
    22 
    23 #endif // DATADELEGATE_H

     

  • datadelegate.cpp
     1 #include "datadelegate.h"
     2 
     3 #include <QDateTimeEdit>
     4 
     5 DataDelegate::DataDelegate(QObject *parent)
     6     : QItemDelegate(parent)
     7 {
     8 
     9 }
    10 
    11 //完成创建控件的工作,创建由参数中的QModelIndex对象指定的表项数据的编辑控件
    12 //并对控件的内容进行限定
    13 QWidget *DataDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    14 {
    15     //新建一个QDataTimeEdit对象作为编辑时的输入控件
    16     QDateTimeEdit *editor = new QDateTimeEdit(parent);
    17     //设置此QDateTimeEdit对象的显示格式为yyyy-MM-dd,此为ISO标准显示方式
    18     //日期的显示格式有很多种,可设定为:
    19     //yy.MM.dd  14.01.01
    20     //d.MM.yyyy 1.01.2014
    21     //其中,y表示年,M表示月份(必须大写),d表示日
    22     editor->setDisplayFormat("yyyy-MM-dd");
    23     //设置日历选择的显示以Popup的方式,即下拉菜单方式显示
    24     editor->setCalendarPopup(true);
    25     //调用QObject类的installEventFilter()函数安装事件过滤器,使DataDelegate
    26     //能够捕获QDateTimeEdit对象的事件
    27     editor->installEventFilter(const_cast<DataDelegate *>(this));
    28     return editor;
    29 
    30 }
    31 
    32 //设置控件显示的数据,将Model中的数据更新至Delegate中,相当于一个初始化工作
    33 void DataDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    34 {
    35     //获取指定index数据项的数据.调用QModelIndex的model()函数可以获得提供index的Model对象
    36     //data()函数返回的是一个QVariant对象,toString()函数将它转换为一个QString类型数据
    37     QString dateStr=index.model()->data(index).toString();
    38     //通过QDate的fromString()函数将以QString类型表示的日期数据转换为QDate类型.
    39     //Qt::ISODate表示QDate类型的日期是以ISO格式保存的,这样最终转换获得的QDate数据也是ISO格式
    40     //使控件显示与表格显示保持一致
    41     QDate date = QDate::fromString(dateStr,Qt::ISODate);
    42 
    43     //将editor转换为QDateTimeEdit对象,以获得编辑控件的对象指针
    44     QDateTimeEdit *edit=static_cast<QDateTimeEdit*>(editor);
    45     //设置控件的显示数据
    46     edit->setDate(date);
    47 }
    48 
    49 //将Deletate中对数据的改变更新至Model中
    50 void DataDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    51 {
    52     //通过紧缩转换获得编辑控件的对象指针
    53     QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor);
    54     //获得编辑控件中的数据更新
    55     QDate date = edit->date();
    56     //调用setDat()函数将数据修改更新到Model中
    57     model->setData(index,QVariant(date.toString(Qt::ISODate)));
    58 }
    59 
    60 //更新控件区的显示
    61 void DataDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    62 {
    63     editor->setGeometry(option.rect);
    64 }

     

  • combodelegate.h
     1 #ifndef COMBODELEGATE_H
     2 #define COMBODELEGATE_H
     3 
     4 #include <QItemDelegate>
     5 
     6 class ComboDelegate : public QItemDelegate
     7 {
     8     Q_OBJECT
     9 
    10 public:
    11     ComboDelegate(QObject *parent=0);
    12 
    13     //完成创建控件的工作,创建由参数中的QModelIndex对象指定的表项数据的编辑控件
    14     //并对控件的内容进行限定
    15     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    16     //设置控件显示的数据,将Model中的数据更新至Delegate中,相当于一个初始化工作
    17     void setEditorData(QWidget *editor,const QModelIndex &index) const;
    18     //将Deletate中对数据的改变更新至Model中
    19     void setModelData(QWidget *editor,QAbstractItemModel *model,const QModelIndex &index) const;
    20     //更新控件区的显示
    21     void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex &index) const;
    22 };
    23 
    24 
    25 
    26 #endif // COMBODELEGATE_H

     

  • combodelegate.cpp
     1 #include "combodelegate.h"
     2 #include <QComboBox>
     3 
     4 ComboDelegate::ComboDelegate(QObject *parent)
     5         :QItemDelegate(parent)
     6 {
     7 
     8 }
     9 
    10 //创建一个QComboBox控件,并插入可显示的条目,安装事件过滤器
    11 QWidget *ComboDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    12 {
    13     QComboBox *editor = new QComboBox(parent);
    14     editor->addItem("工人");
    15     editor->addItem("农民");
    16     editor->addItem("医生");
    17     editor->addItem("律师");
    18     editor->addItem("军人");
    19 
    20     editor->installEventFilter(const_cast<ComboDelegate*>(this));
    21     return editor;
    22 }
    23 
    24 //更新Delegate控件的数据显示(双击时调用)
    25 void ComboDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    26 {
    27 
    28     QString str = index.model()->data(index).toString();
    29 
    30     QComboBox *box = static_cast<QComboBox *>(editor);
    31     int i=box->findText(str);
    32     box->setCurrentIndex(i);
    33 }
    34 
    35 
    36 //setModelData()函数中更新了Model中的数据
    37 void ComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    38 {
    39     QComboBox *box = static_cast<QComboBox*>(editor);
    40 
    41     QString str = box->currentText();
    42     model->setData(index,str);
    43 }
    44 
    45 //更新控件区的显示区域
    46 void ComboDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    47 {
    48     editor->setGeometry(option.rect);
    49 }

     

  • spindelegate.h
     1 #ifndef SPINDELEGATE_H
     2 #define SPINDELEGATE_H
     3 
     4 #include <QItemDelegate>
     5 
     6 class SpinDelegate : public QItemDelegate
     7 {
     8 public:
     9     SpinDelegate(QObject *parent = 0);
    10 
    11     //完成创建控件的工作,创建由参数中的QModelIndex对象指定的表项数据的编辑控件
    12     //并对控件的内容进行限定
    13     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    14     //设置控件显示的数据,将Model中的数据更新至Delegate中,相当于一个初始化工作
    15     void setEditorData(QWidget *editor,const QModelIndex &index) const;
    16     //将Deletate中对数据的改变更新至Model中
    17     void setModelData(QWidget *editor,QAbstractItemModel *model,const QModelIndex &index) const;
    18     //更新控件区的显示
    19     void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex &index) const;
    20 };
    21 
    22 
    23 #endif // SPINDELEGATE_H

     

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

     

  • main.cpp
     1 #include "mainwindow.h"
     2 #include <QApplication>
     3 
     4 #include <QApplication>
     5 #include <QStandardItemModel>
     6 #include <QTableView>
     7 #include <QFile>
     8 #include <QTextStream>
     9 
    10 #include "datadelegate.h"
    11 #include "combodelegate.h"
    12 #include "spindelegate.h"
    13 
    14 int main(int argc, char *argv[])
    15 {
    16     QApplication a(argc, argv);
    17 
    18     QStandardItemModel model(4,4);
    19     QTableView tableView;
    20     tableView.setModel(&model);
    21 
    22 
    23     DataDelegate dateDelegate;
    24     //第一列与dataDelegate关联
    25     tableView.setItemDelegateForColumn(1,&dateDelegate);
    26 
    27     ComboDelegate ComboDelegate;
    28     tableView.setItemDelegateForColumn(2,&ComboDelegate);
    29 
    30     SpinDelegate SpinDelegate;
    31     tableView.setItemDelegateForColumn(3,&SpinDelegate);
    32 
    33     model.setHeaderData(0,Qt::Horizontal,QObject::tr("Name"));
    34     model.setHeaderData(1,Qt::Horizontal,QObject::tr("Birthday"));
    35     model.setHeaderData(2,Qt::Horizontal,QObject::tr("Job"));
    36     model.setHeaderData(3,Qt::Horizontal,QObject::tr("Income"));
    37 
    38     QFile file("test.txt");
    39     if(file.open(QFile::ReadOnly|QFile::Text))
    40     {
    41         QTextStream stream(&file);
    42         QString line;
    43 
    44         model.removeRows(0,model.rowCount(QModelIndex()),QModelIndex());
    45 
    46         int row = 0;
    47         do
    48         {
    49             line = stream.readLine();
    50             if(!line.isEmpty())
    51             {
    52                 model.insertRows(row,1,QModelIndex());
    53                 QStringList pieces = line.split(",",QString::SkipEmptyParts);
    54                 model.setData(model.index(row,0,QModelIndex()),pieces.value(0));
    55                 model.setData(model.index(row,1,QModelIndex()),pieces.value(1));
    56                 model.setData(model.index(row,2,QModelIndex()),pieces.value(2));
    57                 model.setData(model.index(row,3,QModelIndex()),pieces.value(3));
    58                 row++;
    59             }
    60         }while(!line.isEmpty());
    61 
    62         file.close();
    63     }
    64 
    65     tableView.setWindowTitle(QObject::tr("Delegate"));
    66     tableView.show();
    67 
    68     return a.exec();
    69 }

     

posted @ 2018-04-15 23:56  喵小喵~  阅读(1446)  评论(0编辑  收藏  举报