QT MVC 技术Model/View初探
[+]
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所示。
利用Delegate的方式实现表格中嵌入各种不同控件的效果,控件在需要编辑数据项时才出现。
(1)插入日历编辑框QDateLineEdit
[cpp]view plaincopy
#ifndefDATEDELEGATE_H
#defineDATEDELEGATE_H
#include<QtGui>
classDateDelegate:publicQItemDelegate
{
Q_OBJECT
public:
DateDelegate(QObject*parent=0);
QWidget*createEditor(QWidget*parent,constQStyleOptionViewItem&option,
constQModelIndex&index)const;
voidsetEditorData(QWidget*editor,constQModelIndex&index)const;
voidsetModelData(QWidget*editor,QAbstractItemModel*model,
constQModelIndex&index)const;
voidupdateEditorGeometry(QWidget*editor,
constQStyleOptionViewItem&option,constQModelIndex&index)const;
};
#endif
[cpp]view plaincopy
#include"datedelegate.h"
DateDelegate::DateDelegate(QObject*parent)
:QItemDelegate(parent)
{
}
QWidget*DateDelegate::createEditor(QWidget*parent,
constQStyleOptionViewItem&/*option*/,
constQModelIndex&/*index*/)const
{
QDateTimeEdit*editor=newQDateTimeEdit(parent);
editor->setDisplayFormat("yyyy-MM-dd");
editor->setCalendarPopup(true);
editor->installEventFilter(const_cast<DateDelegate*>(this));
returneditor;
}
voidDateDelegate::setEditorData(QWidget*editor,
constQModelIndex&index)const
{
QStringdateStr=index.model()->data(index).toString();
QDatedate=QDate::fromString(dateStr,Qt::ISODate);
QDateTimeEdit*edit=static_cast<QDateTimeEdit*>(editor);
edit->setDate(date);
}
voidDateDelegate::setModelData(QWidget*editor,QAbstractItemModel*model,
constQModelIndex&index)const
{
QDateTimeEdit*edit=static_cast<QDateTimeEdit*>(editor);
QDatedate=edit->date();
model->setData(index,QVariant(date.toString(Qt::ISODate)));
}
voidDateDelegate::updateEditorGeometry(QWidget*editor,
constQStyleOptionViewItem&option,constQModelIndex&/*index*/)const
{
editor->setGeometry(option.rect);
}
分析:DateDelegate继承QItemDelegate,一般需要重定义声明中的几个虚函数。createEditor()函数完成创建控件的工作;setEditorDate()设置控件显示的数据,把Model数据更新至Delegate,相当于初始化工作;setModelDate()把Delegate中对数据的更改更新至Model中;updateEditor()更析控件区的显示。
(2)插入下拉列表框QComboBox
[cpp]view plaincopy
#include"combodelegate.h"
ComboDelegate::ComboDelegate(QObject*parent)
:QItemDelegate(parent)
{
}
QWidget*ComboDelegate::createEditor(QWidget*parent,
constQStyleOptionViewItem&/*option*/,
constQModelIndex&/*index*/)const
{
QComboBox*editor=newQComboBox(parent);
editor->addItem(QString::fromLocal8Bit("工人"));
editor->addItem(QString::fromLocal8Bit("农民"));
editor->addItem(QString::fromLocal8Bit("医生"));
editor->addItem(QString::fromLocal8Bit("律师"));
editor->addItem(QString::fromLocal8Bit("军人"));
editor->installEventFilter(const_cast<ComboDelegate*>(this));
returneditor;
}
voidComboDelegate::setEditorData(QWidget*editor,
constQModelIndex&index)const
{
QStringstr=index.model()->data(index).toString();
QComboBox*box=static_cast<QComboBox*>(editor);
inti=box->findText(str);
box->setCurrentIndex(i);
}
voidComboDelegate::setModelData(QWidget*editor,QAbstractItemModel*model,
constQModelIndex&index)const
{
QComboBox*box=static_cast<QComboBox*>(editor);
QStringstr=box->currentText();
model->setData(index,str);
}
voidComboDelegate::updateEditorGeometry(QWidget*editor,
constQStyleOptionViewItem&option,constQModelIndex&/*index*/)const
{
editor->setGeometry(option.rect);
}
(3)插入微调器QSpinBox
[cpp]view plaincopy
#include"spindelegate.h"
SpinDelegate::SpinDelegate(QObject*parent)
:QItemDelegate(parent)
{
}
QWidget*SpinDelegate::createEditor(QWidget*parent,
constQStyleOptionViewItem&/*option*/,
constQModelIndex&/*index*/)const
{
QSpinBox*editor=newQSpinBox(parent);
editor->setRange(1000,10000);
editor->installEventFilter(const_cast<SpinDelegate*>(this));
returneditor;
}
voidSpinDelegate::setEditorData(QWidget*editor,
constQModelIndex&index)const
{
intvalue=index.model()->data(index).toInt();
QSpinBox*spin=static_cast<QSpinBox*>(editor);
spin->setValue(value);
}
voidSpinDelegate::setModelData(QWidget*editor,QAbstractItemModel*model,
constQModelIndex&index)const
{
QSpinBox*spin=static_cast<QSpinBox*>(editor);
intvalue=spin->value();
model->setData(index,value);
}
voidSpinDelegate::updateEditorGeometry(QWidget*editor,
constQStyleOptionViewItem&option,constQModelIndex&/*index*/)const
{
editor->setGeometry(option.rect);
}
自定义的View实现一个柱状统计图对TableModel的表格数据进行显示。
[cpp]view plaincopy
#ifndefHISTOGRAMVIEW_H
#defineHISTOGRAMVIEW_H
#include<QtGui>
classHistogramView:publicQAbstractItemView
{
Q_OBJECT
public:
HistogramView(QWidget*parent=0);
QRectvisualRect(constQModelIndex&index)const;
voidscrollTo(constQModelIndex&index,ScrollHinthint=EnsureVisible);
QModelIndexindexAt(constQPoint&point)const;
voidpaintEvent(QPaintEvent*);
voidmousePressEvent(QMouseEvent*);
voidsetSelectionModel(QItemSelectionModel*selectionModel);
QRegionitemRegion(QModelIndexindex);
protectedslots:
voiddataChanged(constQModelIndex&topLeft,constQModelIndex&bottomRight);
voidselectionChanged(constQItemSelection&selected,constQItemSelection&deselected);
protected:
QModelIndexmoveCursor(QAbstractItemView::CursorActioncursorAction,
Qt::KeyboardModifiersmodifiers);
inthorizontalOffset()const;
intverticalOffset()const;
boolisIndexHidden(constQModelIndex&index)const;
voidsetSelection(constQRect&rect,QItemSelectionModel::SelectionFlagsflags);
QRegionvisualRegionForSelection(constQItemSelection&selection)const;
private:
QItemSelectionModel*selections;
QList<QRegion>listRegionM;
QList<QRegion>listRegionF;
QList<QRegion>listRegionS;
};
#endif
[cpp]view plaincopy
#include"histogramview.h"
HistogramView::HistogramView(QWidget*parent)
:QAbstractItemView(parent)
{}
voidHistogramView::dataChanged(constQModelIndex&topLeft,constQModelIndex&bottomRight)
{
QAbstractItemView::dataChanged(topLeft,bottomRight);
viewport()->update();
}
QRectHistogramView::visualRect(constQModelIndex&index)const
{}
voidHistogramView::scrollTo(constQModelIndex&index,ScrollHinthint)
{}
QModelIndexHistogramView::indexAt(constQPoint&point)const
{
QPointnewPoint(point.x(),point.y());
QRegionregion;
foreach(region,listRegionM)
{
if(region.contains(newPoint))
{
introw=listRegionM.indexOf(region);
QModelIndexindex=model()->index(row,3,rootIndex());
returnindex;
}
}
returnQModelIndex();
}
QModelIndexHistogramView::moveCursor(QAbstractItemView::CursorActioncursorAction,
Qt::KeyboardModifiersmodifiers)
{}
intHistogramView::horizontalOffset()const
{
}
intHistogramView::verticalOffset()const
{}
boolHistogramView::isIndexHidden(constQModelIndex&index)const
{}
voidHistogramView::setSelectionModel(QItemSelectionModel*selectionModel)
{
selections=selectionModel;
}
voidHistogramView::mousePressEvent(QMouseEvent*e)
{
QAbstractItemView::mousePressEvent(e);
setSelection(QRect(e->pos().x(),e->pos().y(),1,1),QItemSelectionModel::SelectCurrent);
}
QRegionHistogramView::itemRegion(QModelIndexindex)
{
QRegionregion;
if(index.column()==3)
region=listRegionM[index.row()];
returnregion;
}
voidHistogramView::setSelection(constQRect&rect,QItemSelectionModel::SelectionFlagsflags)
{
introws=model()->rowCount(rootIndex());
intcolumns=model()->columnCount(rootIndex());
QModelIndexselectedIndex;
for(introw=0;row<rows;++row)
{
for(intcolumn=1;column<columns;++column)
{
QModelIndexindex=model()->index(row,column,rootIndex());
QRegionregion=itemRegion(index);
if(!region.intersected(rect).isEmpty())
selectedIndex=index;
}
}
if(selectedIndex.isValid())
selections->select(selectedIndex,flags);
else
{
QModelIndexnoIndex;
selections->select(noIndex,flags);
}
}
QRegionHistogramView::visualRegionForSelection(constQItemSelection&selection)const
{}
voidHistogramView::selectionChanged(constQItemSelection&selected,constQItemSelection&deselected)
{
viewport()->update();
}
voidHistogramView::paintEvent(QPaintEvent*)
{
QPainterpainter(viewport());
painter.setPen(Qt::black);
intx0=40;
inty0=250;
//drawcoordinate
painter.drawLine(x0,y0,40,30);
painter.drawLine(38,32,40,30);
painter.drawLine(40,30,42,32);
painter.drawText(5,45,tr("income"));
for(inti=1;i<5;i++){
painter.drawLine(-1,-i*50,1,-i*50);
painter.drawText(-20,-i*50,tr("%1").arg(i*5));
}
//x轴
painter.drawLine(x0,y0,540,250);
painter.drawLine(538,248,540,250);
painter.drawLine(540,250,538,252);
painter.drawText(500,270,tr("name"));
introw;
//name
intposD=x0+20;
for(row=0;row<model()->rowCount(rootIndex());row++)
{
QModelIndexindex=model()->index(row,0,rootIndex());
QStringdep=model()->data(index).toString();
painter.drawText(posD,y0+20,dep);
posD+=50;
}
//income
intposM=x0+20;
for(row=0;row<model()->rowCount(rootIndex());row++)
{
QModelIndexindex=model()->index(row,3,rootIndex());
intincome=model()->data(index).toDouble();
intwidth=10;
if(selections->isSelected(index))
painter.setBrush(QBrush(Qt::darkBlue,Qt::SolidPattern));
else
painter.setBrush(Qt::blue);
painter.drawRect(QRectF(posM+10,y0-income/25,width,income/25));
QRegionregionM(posM+10,y0-income/25,width,income/25);
listRegionM<<regionM;
posM+=50;
}
}
分析:对父类的QAbstractItemView中的所有纯虚函数都必须进行声明,纯虚函数包括visualRect()、scrollTo()、indexAt()、moveCursor()、horizontalOffset()、verticalOffset()、isIndexHidden()、setSelection()和visualRegionForSelection(),这些函数并不一定都要实现,根据功能要求选择实现。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。