這是我對Qt的model/view內容理解的第二篇blog,在第一篇文章中,介紹QTableView和QAbstractTableModel,實現顯示了對數據源的顯示,可是顯示的格式和修改的模式都是按照View控件的自顯示方式。在此,使用Qt自帶的QStyledItemDelegate類實現對特定行/列的顯示/修改模式實現,實現過程當中不出現對item的代碼生成,對item的生成由程序自動完成。c++
在此一樣以《c++ gui programming with Qt4》中的trackEditor例子做一講解。ui
在此,咱們首先應當考慮如下幾個問題:this
1)有一個代理類加到View中,處理特定的View內容。spa
2)代理類要完成如下幾項工做:a)當用戶修改數據時生成用戶要求的控件(用戶每次修改數據時在相應的位置都會生成控件,因此當控件用完後,應del釋放資源)。b)設置在生成的修改控件中顯示的內容。c)設置要寫到model中的數據內容。d)設置當結束脩改數據後,View顯示的內容。.net
在此咱們須要實現如下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。code
Track h文件
orm
#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文件blog
#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