Qt的伪MVC Model-View-Delegate

2017-1-22 Plan C Qt

www.kurukurumi.com原创,转载请注明出处。

E-mail:hubenchang0515@outlook.com


        MVC即模型(Model)-视图(View)-控制器(Controller),是一种软件设计典范,用以将数据模型、用户界面和业务逻辑进行分割。

        先来看一段简单的代码,这里视图是QTableView,模型是QFileSystemModel。

#include <QApplication>
#include <QTableView>
#include <QFileSystemModel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    /* 创建View和Model */
    QTableView view;
    QFileSystemModel model;
    view.setModel(&model);
    view.show();
    model.setRootPath(QDir::currentPath());
    view.setRootIndex(model.index(QDir::currentPath()));

    return app.exec();
}

        然后我们把视图改成QTreeView,模型仍然是QFileSystem不变。

#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    /* 创建View和Model */
    QTreeView view;
    QFileSystemModel model;
    view.setModel(&model);
    view.show();
    model.setRootPath(QDir::currentPath());
    view.setRootIndex(model.index(QDir::currentPath()));

    return app.exec();
}

        MVC能够使模型和视图保持独立,同一个数据模型可以用不同的视图显示出来,同一个视图也能显示不同的数据模型。

        Qt的视图主要有QTableViewQTreeViewQListView

        Qt的模型主要有QStandardItemModelQFileSystemModel

        下面一段代码使用QTableViewQStandardItemModel显示一个表格,双击其中的条目可以编辑, Qt的model会替我们释放其中Item的指针。

#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QStandardItem>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    /* 创建View和Model */
    QTableView view;
    QStandardItemModel model;
    view.setModel(&model);
    view.show();

    /* 设置列名,从0开始 */
    model.setHorizontalHeaderItem(0,new QStandardItem("Name"));
    model.setHorizontalHeaderItem(1,new QStandardItem("Type"));
    model.setHorizontalHeaderItem(2,new QStandardItem("Size"));

    /* 插入行 */
    QList<QStandardItem*> items1;
    items1 << new QStandardItem("home")
           << new QStandardItem("Directory")
           << new QStandardItem("4096");
    model.appendRow(items1);

    QList<QStandardItem*> items2;
    items2 << new QStandardItem("user1")
           << new QStandardItem("Directory")
           << new QStandardItem("4096");
    model.appendRow(items2);

    QList<QStandardItem*> items3;
    items3 << new QStandardItem("user2")
           << new QStandardItem("Directory")
           << new QStandardItem("4096");
    model.appendRow(items3);

    return app.exec();
}

        把上面代码的视图改成QTreeView,其他不变,看起来和QTableView几乎一样。

        QStandardItem::appenRow函数可以给条目设置子行,修改代码,让后两行变成第一行的子行。

#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    /* 创建View和Model */
    QTreeView view;
    QStandardItemModel model;
    view.setModel(&model);
    view.show();

    /* 设置列名,从0开始 */
    model.setHorizontalHeaderItem(0,new QStandardItem("Name"));
    model.setHorizontalHeaderItem(1,new QStandardItem("Type"));
    model.setHorizontalHeaderItem(2,new QStandardItem("Size"));

    /* 插入行 */
    QList<QStandardItem*> items1;
    items1 << new QStandardItem("home")
           << new QStandardItem("Directory")
           << new QStandardItem("4096");
    model.appendRow(items1);

    QList<QStandardItem*> items2;
    items2 << new QStandardItem("user1")
           << new QStandardItem("Directory")
           << new QStandardItem("4096");
    items1[0]->appendRow(items2);//items2是"home"的子行

    QList<QStandardItem*> items3;
    items3 << new QStandardItem("user2")
           << new QStandardItem("Directory")
           << new QStandardItem("4096");
    items1[0]->appendRow(items3);//items3是"home"的子行

    return app.exec();
}

     

        与MVC不同的是,Qt没有控制器(Controller),而是使用委托(Delegate)来协调模型和视图,使用视图的函数setItemDelegate来设置委托。

        Qt的视图、模型、委托分别继承自QAbstractItemViewQAbstractItemModelQAbstractItemDelegate。它们都是抽象类,不能实例化,但可以继承它们来编写新的视图、模型和委托。

        下面继承QItemDelegate来定义一个委托,使被编辑的条目显示为QSpinBox

#ifndef SPINBOXITEMDELEGATE_H
#define SPINBOXITEMDELEGATE_H

#include <QItemDelegate>
#include <QSpinBox>

class SpinBoxItemDelegate : public QItemDelegate
{
public:
    SpinBoxItemDelegate();

    QWidget* createEditor(QWidget *parent,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const;

    void updateEditorGeometry(QWidget *editor,
                              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;




};

#endif // SPINBOXITEMDELEGATE_H
#include "spinboxitemdelegate.h"

SpinBoxItemDelegate::SpinBoxItemDelegate()
{

}

/* 这个函数负责在编辑条目时创建QSpinBox */
QWidget* SpinBoxItemDelegate::createEditor(QWidget *parent,
                                            const QStyleOptionViewItem &option,
                                            const QModelIndex &index) const
{
    QSpinBox* spinBox = new QSpinBox(parent);
    spinBox->setRange(0,99);
    return spinBox;
}

/* 这个函数负责把QSpinBox显示在正确的位置 */
void SpinBoxItemDelegate::updateEditorGeometry(QWidget *editor,
                                                const QStyleOptionViewItem &option,
                                                const QModelIndex &index) const
{
    editor->setGeometry(option.rect);
}

/* 这个函数负责将编辑条目前的数据复制到QSpinBox上 */
void SpinBoxItemDelegate::setEditorData(QWidget *editor,
                                        const QModelIndex &index) const
{
    int v = index.model()->data(index).toInt();
    static_cast<QSpinBox*>(editor)->setValue(v);
}

/* 这个函数负责将数据保存进数据模型 */
void SpinBoxItemDelegate::setModelData(QWidget *editor,
                                        QAbstractItemModel *model,
                                        const QModelIndex &index) const
{
    QSpinBox* spinBox = static_cast<QSpinBox*>(editor);
    spinBox->interpretText();//产生信号
    model->setData(index,spinBox->value());
}
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QStandardItem>
#include "spinboxitemdelegate.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    /* 创建View和Model */
    QTableView view;
    QStandardItemModel model;
    SpinBoxItemDelegate delegate;
    view.setModel(&model);
    view.setItemDelegate(&delegate);
    view.show();

    /* 插入行 */
    QList<QStandardItem*> items1;
    items1 << new QStandardItem("1")
           << new QStandardItem("2")
           << new QStandardItem("3");
    model.appendRow(items1);

    QList<QStandardItem*> items2;
    items2 << new QStandardItem("4")
           << new QStandardItem("5")
           << new QStandardItem("6");
    model.appendRow(items2);

    QList<QStandardItem*> items3;
    items3 << new QStandardItem("7")
           << new QStandardItem("8")
           << new QStandardItem("9");
    model.appendRow(items3);

    return app.exec();
}

发表评论:

Powered by emlog
鄂ICP备16003833号