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

帅比萌擦擦* 提交于 2020-03-02 02:45:25

这是我对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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!