您好,登錄后才能下訂單哦!
[+]
Model/View結(jié)構(gòu)使數(shù)據(jù)管理與相應(yīng)的數(shù)據(jù)顯示相互獨立,并提供了一系列標(biāo)準(zhǔn)的函數(shù)接口和用于Model模塊與View模塊之間的通信。它從MVC演化而來,MVC由三種對象組成,Model是應(yīng)用程序?qū)ο?,View是它的屏幕表示,Controller定義了用戶界面如何對用戶輸入進行響應(yīng)。把MVC中的View和Controller合在一起,就形成了Model/View結(jié)構(gòu)。
(1)為了靈活對用戶的輸入進行處理,引入了Delegate,Model、View、Delegate三個模塊之間通過信號與槽機制實現(xiàn),當(dāng)自身的狀態(tài)發(fā)生改變時會發(fā)出信號通知其他模塊。它們間的關(guān)系如下圖1所示。
QAbstractItemModel是所有Model的基類,但一般不直接使用QAbstractItemModel,而是使用它的子類。Model模塊本身并不存儲數(shù)據(jù),而是為View和Delegate訪問數(shù)據(jù)提供標(biāo)準(zhǔn)的接口。
View模塊從Model中獲得數(shù)據(jù)項顯示給用戶,Qt提供了一些常用的View模型,如QTreeView、QTableView和QListView。
Delegate的基本接口在QAbstractItemDelegate類中定義,通過實現(xiàn)paint()和sizeHint()以達到渲染數(shù)據(jù)項的目的。
(2)程序運行圖如下圖2所示。
利用Delegate的方式實現(xiàn)表格中嵌入各種不同控件的效果,控件在需要編輯數(shù)據(jù)項時才出現(xiàn)。
(1)插入日歷編輯框QDateLineEdit
[cpp] view plain copy
#ifndef DATEDELEGATE_H
#define DATEDELEGATE_H
#include <QtGui>
class DateDelegate : public QItemDelegate
{
Q_OBJECT
public:
DateDelegate(QObject *parent = 0);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif
[cpp] view plain copy
#include "datedelegate.h"
DateDelegate::DateDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *DateDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QDateTimeEdit *editor = new QDateTimeEdit(parent);
editor->setDisplayFormat("yyyy-MM-dd");
editor->setCalendarPopup(true);
editor->installEventFilter(const_cast<DateDelegate*>(this));
return editor;
}
void DateDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QString dateStr = index.model()->data(index).toString();
QDate date = QDate::fromString(dateStr,Qt::ISODate);
QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor);
edit->setDate(date);
}
void DateDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QDateTimeEdit *edit = static_cast<QDateTimeEdit*>(editor);
QDate date = edit->date();
model->setData(index, QVariant(date.toString(Qt::ISODate)));
}
void DateDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
分析:DateDelegate繼承QItemDelegate,一般需要重定義聲明中的幾個虛函數(shù)。createEditor()函數(shù)完成創(chuàng)建控件的工作;setEditorDate()設(shè)置控件顯示的數(shù)據(jù),把Model數(shù)據(jù)更新至Delegate,相當(dāng)于初始化工作;setModelDate()把Delegate中對數(shù)據(jù)的更改更新至Model中;updateEditor()更析控件區(qū)的顯示。
(2)插入下拉列表框QComboBox
[cpp] view plain copy
#include "combodelegate.h"
ComboDelegate::ComboDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *ComboDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem(QString::fromLocal8Bit("工人"));
editor->addItem(QString::fromLocal8Bit("農(nóng)民"));
editor->addItem(QString::fromLocal8Bit("醫(yī)生"));
editor->addItem(QString::fromLocal8Bit("律師"));
editor->addItem(QString::fromLocal8Bit("軍人"));
editor->installEventFilter(const_cast<ComboDelegate*>(this));
return editor;
}
void ComboDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QString str = index.model()->data(index).toString();
QComboBox *box = static_cast<QComboBox*>(editor);
int i = box->findText(str);
box->setCurrentIndex(i);
}
void ComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QComboBox *box = static_cast<QComboBox*>(editor);
QString str = box->currentText();
model->setData(index, str);
}
void ComboDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
(3)插入微調(diào)器QSpinBox
[cpp] view plain copy
#include "spindelegate.h"
SpinDelegate::SpinDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *SpinDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setRange(1000,10000);
editor->installEventFilter(const_cast<SpinDelegate*>(this));
return editor;
}
void SpinDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index).toInt();
QSpinBox *spin = static_cast<QSpinBox*>(editor);
spin->setValue(value);
}
void SpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spin = static_cast<QSpinBox*>(editor);
int value = spin->value();
model->setData(index, value);
}
void SpinDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
自定義的View實現(xiàn)一個柱狀統(tǒng)計圖對TableModel的表格數(shù)據(jù)進行顯示。
[cpp] view plain copy
#ifndef HISTOGRAMVIEW_H
#define HISTOGRAMVIEW_H
#include <QtGui>
class HistogramView : public QAbstractItemView
{
Q_OBJECT
public:
HistogramView(QWidget *parent=0);
QRect visualRect(const QModelIndex &index)const;
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible);
QModelIndex indexAt(const QPoint &point) const;
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *);
void setSelectionModel(QItemSelectionModel * selectionModel);
QRegion itemRegion(QModelIndex index);
protected slots:
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected );
protected:
QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,
Qt::KeyboardModifiers modifiers);
int horizontalOffset() const;
int verticalOffset() const;
bool isIndexHidden(const QModelIndex &index) const;
void setSelection ( const QRect&rect, QItemSelectionModel::SelectionFlags flags );
QRegion visualRegionForSelection(const QItemSelection &selection) const;
private:
QItemSelectionModel *selections;
QList<QRegion> listRegionM;
QList<QRegion> listRegionF;
QList<QRegion> listRegionS;
};
#endif
[cpp] view plain copy
#include "histogramview.h"
HistogramView::HistogramView(QWidget *parent)
: QAbstractItemView(parent)
{}
void HistogramView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
QAbstractItemView::dataChanged(topLeft, bottomRight);
viewport()->update();
}
QRect HistogramView::visualRect(const QModelIndex &index) const
{}
void HistogramView::scrollTo(const QModelIndex &index, ScrollHint hint)
{}
QModelIndex HistogramView::indexAt(const QPoint &point) const
{
QPoint newPoint(point.x(),point.y());
QRegion region;
foreach(region,listRegionM)
{
if (region.contains(newPoint))
{
int row = listRegionM.indexOf(region);
QModelIndex index = model()->index(row, 3,rootIndex());
return index;
}
}
return QModelIndex();
}
QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction,
Qt::KeyboardModifiers modifiers)
{}
int HistogramView::horizontalOffset() const
{
}
int HistogramView::verticalOffset() const
{}
bool HistogramView::isIndexHidden(const QModelIndex &index) const
{}
void HistogramView::setSelectionModel(QItemSelectionModel * selectionModel)
{
selections = selectionModel;
}
void HistogramView::mousePressEvent(QMouseEvent *e)
{
QAbstractItemView::mousePressEvent(e);
setSelection(QRect(e->pos().x(),e->pos().y(),1,1),QItemSelectionModel::SelectCurrent);
}
QRegion HistogramView::itemRegion(QModelIndex index)
{
QRegion region;
if (index.column() == 3)
region = listRegionM[index.row()];
return region;
}
void HistogramView::setSelection ( const QRect &rect, QItemSelectionModel::SelectionFlags flags )
{
int rows = model()->rowCount(rootIndex());
int columns = model()->columnCount(rootIndex());
QModelIndex selectedIndex;
for (int row = 0; row < rows; ++row)
{
for (int column = 1; column < columns; ++column)
{
QModelIndex index = model()->index(row, column, rootIndex());
QRegion region = itemRegion(index);
if (!region.intersected(rect).isEmpty())
selectedIndex = index;
}
}
if(selectedIndex.isValid())
selections->select(selectedIndex,flags);
else
{
QModelIndex noIndex;
selections->select(noIndex, flags);
}
}
QRegion HistogramView::visualRegionForSelection(const QItemSelection &selection) const
{}
void HistogramView::selectionChanged(const QItemSelection & selected, const QItemSelection & deselected )
{
viewport()->update();
}
void HistogramView::paintEvent(QPaintEvent *)
{
QPainter painter(viewport());
painter.setPen(Qt::black);
int x0 = 40;
int y0 = 250;
// draw coordinate
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 (int i=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"));
int row;
// name
int posD = x0+20;
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;
}
// income
int posM = x0+20;
for (row = 0; row < model()->rowCount(rootIndex()); row++)
{
QModelIndex index = model()->index(row, 3, rootIndex());
int income = model()->data(index).toDouble();
int width = 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));
QRegion regionM(posM + 10, y0-income/25, width, income/25);
listRegionM << regionM;
posM += 50;
}
}
分析:對父類的QAbstractItemView中的所有純虛函數(shù)都必須進行聲明,純虛函數(shù)包括visualRect()、scrollTo()、indexAt()、moveCursor()、horizontalOffset()、verticalOffset()、isIndexHidden()、setSelection()和visualRegionForSelection(),這些函數(shù)并不一定都要實現(xiàn),根據(jù)功能要求選擇實現(xiàn)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。