赞
踩
MVC是一种我们熟知的架构模式,它的全称是 Model View Controller。MVC具体的概念及应用,网上已经非常非常详尽了,这里就不赘述了,今天要了解的是其在Qt中的具体应用。Qt中的MVC并不叫MVC,而是叫MVD,Qt中没有Controller的说法,而是使用了另外一种抽象: Delegate (委托) ,其行为和传统的MVC是相同的。
基于抽象基类QAbstractItemModel类,其继承类有:
基于抽象基类QAbstractItemView类,其继承类有:
基于抽象基类QAbstractItemDelegate类,其继承类有:
例子是电子工业出版社的《Qt5开发及实例》一书中的内容。
① 使用QDirModel基类,将QTreeView、QTableView、QListView的模型设为QDirModel实现下图:
int main(int argc, char *argv[]) { QApplication a(argc, argv); QDirModel model; QTreeView tree; QListView list; QTableView table; tree.setModel(&model); list.setModel(&model); table.setModel(&model); tree.setSelectionMode(QAbstractItemView::SingleSelection); list.setSelectionModel(tree.selectionModel()); table.setSelectionModel(tree.selectionModel()); QObject::connect(&tree,SIGNAL(doubleClicked(QModelIndex)),&list,SLOT(setRootIndex(QModelIndex))); QObject::connect(&tree,SIGNAL(doubleClicked(QModelIndex)),&table,SLOT(setRootIndex(QModelIndex))); QSplitter *splitter = new QSplitter; splitter->addWidget(&tree); splitter->addWidget(&list); splitter->addWidget(&table); splitter->setWindowTitle(QObject::tr("Model/View")); splitter->show(); return a.exec(); }
自定义QAbstractTableModel类,将QtableView的模型设置为自定义模型,实现:
modelx是一个继承于QAbstractTableModel的类,modelx.cpp如下:
#include "modelex.h" #pragma execution_character_set("utf-8") ModelEx::ModelEx(QObject *parent) : QAbstractTableModel(parent) { armyMap[1]=tr("空军"); armyMap[2]=tr("海军"); armyMap[3]=tr("陆军"); armyMap[4]=tr("海军陆战队"); weaponTypeMap[1]=tr("轰炸机"); weaponTypeMap[2]=tr("战斗机"); weaponTypeMap[3]=tr("航空母舰"); weaponTypeMap[4]=tr("驱逐舰"); weaponTypeMap[5]=tr("直升机"); weaponTypeMap[6]=tr("坦克"); weaponTypeMap[7]=tr("两栖攻击舰"); weaponTypeMap[8]=tr("两栖战车"); populateModel(); } void ModelEx::populateModel() { header<<tr("军种")<<tr("种类")<<tr("武器"); army<<1<<2<<3<<4<<2<<4<<3<<1; weaponType<<1<<3<<5<<7<<4<<8<<6<<2; weapon<<tr("B-2")<<tr("尼米兹级")<<tr("阿帕奇")<<tr("黄蜂级")<<tr("阿利伯克级")<<tr("AAAV")<<tr("M1A1")<<tr("F-22"); } int ModelEx::columnCount(const QModelIndex &parent) const { return 3; } int ModelEx::rowCount(const QModelIndex &parent) const { return army.size(); } QVariant ModelEx::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); if(role==Qt::DisplayRole) { switch(index.column()) { case 0: return armyMap[army[index.row()]]; break; case 1: return weaponTypeMap[weaponType[index.row()]]; break; case 2: return weapon[index.row()]; default: return QVariant(); } } return QVariant(); } QVariant ModelEx::headerData(int section, Qt::Orientation orientation, int role) const { if(role==Qt::DisplayRole&&orientation==Qt::Horizontal) return header[section]; return QAbstractTableModel::headerData(section,orientation,role); }
(☆)表格是QTableView,不多做讲解。重点是柱状统计图绘制,这里使用的自定义的QAbstractItemView,model使用的是标准的QStandardItemModel,效果如图:这里还使用了QItemSelectionModel来实现表格与柱状图的联动。
这里不论是网上给的还是书上给的教程都有点问题,源代码需要进行修正。其一,一些重载函数虽然没有具体实现,但是需要给返回值;其二,在定义柱状图的点击事件时,出现了问题(点击柱状图时没有预期的反应)。自己定义的histogramview类中的用来存储各个柱状的位置信息的链表构建有误需要进行修改。
这里只放出我的修改部分。
首先是重载函数的返回值部分。
由于这些重载函数没有被使用到,其返回值不重要,创建一些空对象即可。
QRect HistogramView::visualRect(const QModelIndex &index)const{ return QRect(); } void HistogramView::scrollTo(const QModelIndex &index,ScrollHint){} QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers){ return QModelIndex(); } int HistogramView::horizontalOffset()const{ return 0; } int HistogramView::verticalOffset()const{ return 0; } bool HistogramView::isIndexHidden(const QModelIndex &index)const{ return true; } QRegion HistogramView::visualRegionForSelection(const QItemSelection &selection)const{ return QRegion(); }
然后是对柱状图点击效果的修改。
首先,我再mainwindow.cpp文件中声明了一个全局变量标志位g_regFlag,初始化为false;每一次打开新文件时置为true;
void MainWindow::openFile(QString path) { if (!path.isEmpty()) { QFile file(path); if (file.open(QFile::ReadOnly|QFile::Text)) { QTextStream stream(&file); QString line; model->removeRows(0,model->rowCount(QModelIndex()),QModelIndex()); g_regFlag=true; int row = 0; do { line = stream.readLine(); if (!line.isEmpty()) { model->insertRows(row, 1, QModelIndex()); QStringList pieces=line.split(",",QString::SkipEmptyParts); model->setData(model->index(row, 0, QModelIndex()),pieces.value(0)); model->setData(model->index(row, 1, QModelIndex()),pieces.value(1)); model->setData(model->index(row, 2, QModelIndex()),pieces.value(2)); model->setData(model->index(row, 3, QModelIndex()),pieces.value(3)); row++; } }while (!line.isEmpty()); file.close(); } } }
然后修改绘画函数
// paintEvent()函数具体完成柱状统计图绘制的工作 void HistogramView::paintEvent(QPaintEvent *) { QPainter painter(viewport()); painter.setPen(Qt::black); int x0=40; int y0=250; //y坐标轴 painter.drawLine(x0,y0,40,30); painter.drawLine(38,32,40,30); painter.drawLine(40,30,42,32); painter.drawText(20,30,tr("人数")); for(int i=1;i<5;i++) { painter.drawLine(40,i*50,41,i*50); painter.drawText(20,i*50,tr("%1").arg((5-i)*5)); } //x 坐标轴 painter.drawLine(x0,y0,540,250); painter.drawLine(538,248,540,250); painter.drawLine(540,250,538,252); painter.drawText(545,250,tr("部门")); int posD=x0+20; int row; for(row=0;row<model()->rowCount(rootIndex());row++) { QModelIndex index=model()->index(row,0,rootIndex()); QString dep=model()->data(index).toString(); painter.drawText(posD,y0+20,dep); posD+=50; } if(g_regFlag) //先将前一次的位置信息清除 { MRegionList.clear(); FRegionList.clear(); SRegionList.clear(); } //男 int posM=x0+20; for(row=0;row<model()->rowCount(rootIndex());row++) { QModelIndex index=model()->index(row,1,rootIndex()); int male=model()->data(index).toDouble(); int width=10; if(selections->isSelected(index)) painter.setBrush(QBrush(Qt::blue,Qt::Dense3Pattern)); else painter.setBrush(Qt::blue); painter.drawRect(QRect(posM,y0-male*10,width,male*10)); if(g_regFlag) //避免重复添加位置信息 { QRegion regionM(posM,y0-male*10,width,male*10); MRegionList<<regionM; } posM+=50; } //女 int posF=x0+30; for(row=0;row<model()->rowCount(rootIndex());row++) { QModelIndex index=model()->index(row,2,rootIndex()); int female=model()->data(index).toDouble(); int width=10; if(selections->isSelected(index)) painter.setBrush(QBrush(Qt::red,Qt::Dense3Pattern)); else painter.setBrush(Qt::red); painter.drawRect(QRect(posF,y0-female*10,width,female*10)); if(g_regFlag) { QRegion regionF(posF,y0-female*10,width,female*10); FRegionList<<regionF; } posF+=50; } //退休 int posS=x0+40; for(row=0;row<model()->rowCount(rootIndex());row++) { QModelIndex index=model()->index(row,3,rootIndex()); int retire=model()->data(index).toDouble(); int width=10; if(selections->isSelected(index)) painter.setBrush(QBrush(Qt::green,Qt::Dense3Pattern)); else painter.setBrush(Qt::green); painter.drawRect(QRect(posS,y0-retire*10,width,retire*10)); if(g_regFlag) { QRegion regionS(posS,y0-retire*10,width,retire*10); SRegionList<<regionS; if(row==model()->rowCount(rootIndex())-1) g_regFlag=false; } posS+=50; } }
文件
一部,12,3,5
二部,16,4,0
三部,18,4,2
四部,10,3,1
五部,11,4,3
六部,12,2,4
七部,14,3,5
八部,9,1,1
自定义QAbstractItemDelegate,实现控件只有在需要编辑数据项时才会显示。实现效果如图:
这里自己定义了三个委托类,分别是Date、Combo、Spin类型。
int main(int argc, char *argv[]) { QApplication a(argc, argv); QStandardItemModel model(4,4); QTableView tableView; tableView.setModel(&model); DateDelegate dateDelegate; tableView.setItemDelegateForColumn(1,&dateDelegate); ComboDelegate comboDelegate; tableView.setItemDelegateForColumn(2,&comboDelegate); SpinDelegate spinDelegate; tableView.setItemDelegateForColumn(3,&spinDelegate); model.setHeaderData(0,Qt::Horizontal,QObject::tr("姓名")); model.setHeaderData(1,Qt::Horizontal,QObject::tr("生日")); model.setHeaderData(2,Qt::Horizontal,QObject::tr("职业")); model.setHeaderData(3,Qt::Horizontal,QObject::tr("收入")); QFile file("C:/Users/Bruce/Desktop/456.txt"); if(file.open(QFile::ReadOnly|QFile::Text)) { QTextStream stream(&file); QString line; model.removeRows(0,model.rowCount(QModelIndex()),QModelIndex()); int row =0; do{ line = stream.readLine(); if(!line.isEmpty()) { model.insertRows(row,1,QModelIndex()); QStringList pieces = line.split(",",QString::SkipEmptyParts); model.setData(model.index(row,0,QModelIndex()),pieces.value(0)); model.setData(model.index(row,1,QModelIndex()),pieces.value(1)); model.setData(model.index(row,2,QModelIndex()),pieces.value(2)); model.setData(model.index(row,3,QModelIndex()),pieces.value(3)); row++; } }while(!line.isEmpty()); file.close(); } tableView.setWindowTitle(QObject::tr("Delegate")); tableView.show(); return a.exec(); }
文件
Tom,1997-01-05,工人,1500
Jack,1978-12-23,医生,3000
Alice,1980-04-06,军人,2500
John,1983-09-25,律师,5000
不用积分
源代码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。