这是我对Qt的model/view内容理解的第二篇blog,在第一篇文章中,介绍QTableView和QAbstractTableModel,实现显示了对数据源的显示,但是显示的格式和修改的模式都是按照View控件的自显示方式。在此,使用Qt自带的QStyledItemDelegate类实现对特定行/列的显示/修改模式实现,实现过程中不出现对item的代码生成,对item的生成由程序自动完成。
在此同样以《c++ gui programming with Qt4》中的trackEditor例子作一讲解。
在此,我们首先应当考虑以下几个问题:
1)有一个代理类加到View中,处理特定的View内容。
2)代理类要完成以下几项工作:a)当用户修改数据时生成用户要求的控件(用户每次修改数据时在相应的位置都会生成控件,所以当控件用完后,应del释放资源)。b)设置在生成的修改控件中显示的内容。c)设置要写到model中的数据内容。d)设置当结束修改数据后,View显示的内容。
在此我们需要实现以下4个类。
/**
@brief 保存显示数据的类。
*/
class Track
/**
@brief 继承的委托类。
*/
class TrackDelegate : public QStyledItemDelegate
/**
@brief 继承的模型类。
*/
class TrackModel : public QAbstractTableModel
/**
@brief 用于组装显示的控件类。
*/
class TrackEditor : public QDialog
在此,Track TrackModel TrackEditor的功能在Qt model/view理解1中做过介绍,在此只列出code,不再过多介绍。在此主要介绍TrackDelegate。
Track h文件
#ifndef TRACK_H#define TRACK_H
#include <QString>
/**
@brief 保存显示数据的类。
*/
class Track
{
public:
explicit Track(const QString &title = "", int duration = 0);
~Track();
QString getTitle() const;
int getDuration() const;
void setTitle(QString title);
void setDuration(int duration);
private:
QString title;
int duration;
};
#endif // TRACK_H
TrackModel h文件
#ifndef TRACKMODEL_H#define TRACKMODEL_H
#include <QWidget>
#include <QAbstractTableModel>
#include <QList>
#include "track.h"
#include <QObject>
/**
@brief 继承的模型类。
*/
class TrackModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit TrackModel(QList<Track>* tracks, QObject* parent = 0);
~TrackModel();
virtual int rowCount(const QModelIndex &parent) const;
virtual int columnCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual bool setData(const QModelIndex &index,
const QVariant &value,
int role);
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
private:
QList<Track>* tracks;
};
#endif // TRACKMODEL_H
TrackEditor h文件
#ifndef TRACKEDITOR_H#define TRACKEDITOR_H
#include <QDialog>
#include "track.h"
QT_BEGIN_NAMESPACE
class QTableView;
class TrackModel;
class QAbstractTableModel;
QT_END_NAMESPACE
namespace Ui {
class TrackEditor;
}
/**
@brief 用于组装显示的控件类。
*/
class TrackEditor : public QDialog
{
Q_OBJECT
public:
explicit TrackEditor(QList<Track>* tracks, QWidget *parent = 0);
~TrackEditor();
private:
Ui::TrackEditor *ui;
QTableView* tableView;
TrackModel* model;
//QAbstractTableModel* model;
};
#endif // TRACKEDITOR_H
TrackDelegate h文件
#ifndef TRACKDELEGATE_H#define TRACKDELEGATE_H
#include <QObject>
#include <QStyledItemDelegate>
QT_BEGIN_NAMESPACE
class QPainter;
QT_END_NAMESPACE
/**
@brief 继承的委托类。
*/
class TrackDelegate : public QStyledItemDelegate
{
public:
explicit TrackDelegate(QObject* parent = 0);
~TrackDelegate();
virtual QWidget* createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
virtual void setEditorData(QWidget* parent,
const QModelIndex& index) const;
virtual void setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const;
virtual void updateEditorGeometry(QWidget* editor,
const QStyleOptionViewItem& option,
const QModelIndex& index) const;
virtual void paint(QPainter* painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const;
private:
bool isRightColumn(const QModelIndex& index, const int column) const;
private slots:
void commitAndCloseEditor();
private:
static const int columnNumber;
};
#endif // TRACKDELEGATE_H
TrackDelegate cpp文件
#include "trackdelegate.h"
#include <QTimeEdit>
#include <QPainter>
#include <QApplication>
#include "trackmodel.h"
const int TrackDelegate::columnNumber = 1;
TrackDelegate::TrackDelegate(QObject* parent) :
QStyledItemDelegate(parent)
{
}
TrackDelegate::~TrackDelegate()
{
}
QWidget* TrackDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (isRightColumn(index, TrackDelegate::columnNumber)) {
QTimeEdit *timeEdit = new QTimeEdit(parent);
timeEdit->setDisplayFormat("hh:mm");
//当控件结束编辑内容时,触发释放资源
connect(timeEdit, &QTimeEdit::editingFinished,
this, &TrackDelegate::commitAndCloseEditor);
//int secs = index.model()->data(index, Qt::DisplayRole).toInt();
int secs = index.model()->data(index, Qt::EditRole).toInt();
QTime time(secs / 60, secs % 60);
timeEdit->setTime(time);
return timeEdit;
} else {
return QStyledItemDelegate::createEditor(parent,
option,
index);
}
}
void TrackDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if ( !index.isValid()) {
return;
}
QTimeEdit* timeEditor = qobject_cast<QTimeEdit*>(editor);
if ( !timeEditor) {
return;
}
if (isRightColumn(index, TrackDelegate::columnNumber)) {
int secs = index.model()->data(index, Qt::EditRole).toInt();
QTime time(secs / 60, secs % 60);
timeEditor->setTime(time);
} else {
QStyledItemDelegate::setEditorData(editor, index);
}
}
void TrackDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
if ( !index.isValid()) {
return;
}
QTimeEdit* timeEditor = qobject_cast<QTimeEdit*>(editor);
if ( !timeEditor) {
return;
}
if (isRightColumn(index, TrackDelegate::columnNumber)) {
QTime time = timeEditor->time();
int secs = time.hour() * 60 + time.minute();
model->setData(index, secs, Qt::EditRole);
} else {
QStyledItemDelegate::setModelData(editor,
model,
index);
}
}
void TrackDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
void TrackDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (isRightColumn(index, TrackDelegate::columnNumber)) {
int secs = index.model()->data(index, Qt::EditRole).toInt();
QString text = QString("%1:%2")
.arg(secs / 60, 2, 10, QChar('0'))
.arg(secs % 60, 2, 10, QChar('0'));
//获取项风格设置
QStyleOptionViewItem myOption = option;
myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
painter->drawText(option.rect, text);
} else {
QStyledItemDelegate::paint(painter, option, index);
}
}
QSize TrackDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
return option.rect.size();
}
void TrackDelegate::commitAndCloseEditor()
{
QTimeEdit* editor = qobject_cast<QTimeEdit*>(sender());
emit commitData(editor);
emit closeEditor(editor);
}
bool TrackDelegate::isRightColumn(const QModelIndex &index,
const int column) const
{
if ( !index.isValid()) {
return false;
}
if (index.column() == column) {
return true;
} else {
return false;
}
}
createEditor用于创建用户自己需要的显示数据控件。
setEditorData用于设置显示控件中显示的具体数据信息。
setModelData用户设置模型的数据,也可理解为当显示的数据发生变化后,用户update模型数据,保持显示/储存内容一致。
paint由用户自己绘制要显示的内容信息(很重要,当你点击时间框修改时间,要改的内容为原显示内容并允许你修改,而不是数据变为00:00,让你修改)。
commitAndCloseEditor 创建关于commitData和closeEditor的信号槽链接,保证当代理控件的数据修改完成后,释放信号,保存数据(保存数据步骤由系统自动完成)。
在此要求注意内容:
在TrackModel类中的setData方法应当注意,data的值应从value得出而不是通过model的data得出,model得出的数据是原来保存的,而不是用户修改的。
完整代码见http://www.oschina.net/code/snippet_48549_45036
来源:oschina
链接:https://my.oschina.net/u/48549/blog/362759