- 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 }