Qt model/view理解2:添加代理-20151018更新理解

這是我對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

相關文章
相關標籤/搜索