38.Qt模型/视图结构

Posted 喵小喵~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
    如何防止在背面片段导航上再次设置视图模型

    片段的视图模型

    片段的视图模型而不是访问活动视图模型?

    LiveData 没有观察具有共享视图模型的子视图页面片段

    如何在作为选项卡的 2 个片段之间共享视图模型

    使用 koin 2.2.3 和 jetpack 导航在 2 个片段之间限定视图模型