第63课 深入解析视图与委托(上)

发布时间:2017-1-19 6:10:04 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"第63课 深入解析视图与委托(上) ",主要涉及到第63课 深入解析视图与委托(上) 方面的内容,对于第63课 深入解析视图与委托(上) 感兴趣的同学可以参考一下。

1. model/view模式的回顾

 

(1)model与数据源通讯,并提供接口给别的组件使用。view从model获取model indexes数据项引用并通过model indexes可以从数据源中获取数据

(2)model/view中的通讯

  ①从model发出的信号通知view数据源中的数据发生了改变。

  ②从view发出的信号提供了有关被显示数据项与用户交互的信息

  ③delegate发出的信号被用在通知model和view关于当前编辑器的状态信息。

(3)view从model中读取数据,它可以自己去渲染每个数据项,也可以利用delegate来即处理渲染又进行编辑。view为数据项提供了缺省的编程功能,也可以搭配delegate实现更为特殊的定制编辑的需求

2. 深度思考

(1)Qt中的委托作为视图的内部组件而存在。因此,委托是视图的一部分。必然,委托需要承担数据显示的部分工作

(2)视图负责确定数据项和组织显示方式(如以列表、树形或表格显示)

(3)委托负责具体数据项的显示和编辑(数据值,编辑器)

(4)视图和委托共同完成数据显示功能和数据编辑功能。

3. 拓展的思考:如何改变视图默认的数据显示方式?

(1)自定义委托的默认数据显示方式

  ①重写委托的paint成员函数

  ②在paint中自定义数据显示方式

  ③重写editorEvent成员函数

  ④在editorEvent中处理交互事件

(2)在paint中自定义数据显示方式

//绘制复选框if (index.data().type() == QVariant::Bool ){    bool data = index.data(Qt::DisplayRole).toBool();     QStyleOptionButton checkBoxStyle; //组件绘制参数        //设置具体的绘制参数    checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;    checkBoxStyle.state |= QStyle::State_Enabled;    checkBoxStyle.rect = option.rect;    checkBoxStyle.rect.setX(option.rect.x() + option.rect.width() /2 -6);        //根据参数绘制组件(数据项自定义显示方式)    QApplication::style()->drawControl(QStyle::CE_CheckBox,                                       &checkBoxStyle,                                       painter);}

(3)在editorEvent中处理交互事件

//处理交互事件if ( index.data().type() == QVariant::Bool){    QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);        if(event->type() == QEvent::MouseButtonPress &&       option.rect.contains(mouseEvent->pos()))    {        bool data = index.data(Qt::DisplayRole).toBool();        model->setData(index, !data, Qt::Qt::DisplayRole);    }}

4. 在视图标题栏中添加CheckBox复选框

(1)CheckBoxHeaderView类的设计

  ①继承自QHeaderView

  ②重写paintSection函数(详细代码见《编程实验》)

  ③重写mousePressEvent函数(详细代码见《编程实验》)

  ④添加复选框状态改变时发送的信号void checkBoxClicked(bool state);

(2)更改m_view默认的标题栏为自定义的标题栏

  CheckBoxHeaderView* myHeader = new CheckBoxHeaderView(Qt::Horizontal, &m_view);

  m_view.setHorizontalHeader(myHeader);

(3)添加响应复选框状态变化的槽函数

  void Widget::onCheckBoxHeaderClicked(bool state)

【编程实验】添加复选框

 

//main.cpp

#include "Widget.h"#include <QApplication>int main(int argc, char *argv[]){    QApplication a(argc, argv);    Widget w;    w.show();    return a.exec();}
View Code

//Widget.h

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QTableView>#include <QPushButton>#include <QStandardItemModel>#include "CustomizedItemDelegate.h"class Widget : public QWidget{    Q_OBJECT    QTableView m_view;    QStandardItemModel m_model;    CustomizedItemDelegate m_delegate;    void initView();    void initModel();private slots:    void onCheckBoxHeaderClicked(bool state);public:    Widget(QWidget *parent = 0);    ~Widget();};#endif // WIDGET_H

//Widget.cpp

#include "Widget.h"#include "CheckBoxHeaderView.h"Widget::Widget(QWidget *parent)    : QWidget(parent){    initView();    initModel();    m_view.setModel(&m_model);    m_view.setColumnWidth(m_model.columnCount() -1, 125);}void Widget::initView(){    m_view.setParent(this);    m_view.move(10, 10);    m_view.resize(500, 200);    //在第1列标题栏内添加“全选”复选框    CheckBoxHeaderView* myHeader = new CheckBoxHeaderView(Qt::Horizontal, &m_view);    m_view.setHorizontalHeader(myHeader);    connect(myHeader, SIGNAL(checkBoxClicked(bool)), this,  SLOT(onCheckBoxHeaderClicked(bool)));    //设置视图的委托对象(自定义委托对象)    m_view.setItemDelegate(&m_delegate);}void Widget::initModel(){    QStandardItem* root = m_model.invisibleRootItem();    QStandardItem* itemA1 = new QStandardItem();    QStandardItem* itemB1 = new QStandardItem();    QStandardItem* itemC1 = new QStandardItem();    QStandardItem* itemD1 = new QStandardItem();    QStandardItem* itemA2 = new QStandardItem();    QStandardItem* itemB2 = new QStandardItem();    QStandardItem* itemC2 = new QStandardItem();    QStandardItem* itemD2 = new QStandardItem();    //添加表头    m_model.setColumnCount(4);    m_model.setHeaderData(0,Qt::Horizontal,QString("Select All"),Qt::DisplayRole);    m_model.setHeaderData(1,Qt::Horizontal,QString("Language"),Qt::DisplayRole);    m_model.setHeaderData(2,Qt::Horizontal,QString("Score"),Qt::DisplayRole);    m_model.setHeaderData(3,Qt::Horizontal,QString("Level"),Qt::DisplayRole);    //添加复选框的方法:    //1. 直接设置数据角色,如:itemA1->setData(false,Qt::CheckStateRole);    //   该方法的好象是直接、简单,但所绘制出来的复选框不好控制(如设置居中对齐方式等)    //2. 方法2:在delegate的paint函数中绘制并处理editorEvent事件,该方法的好处是可以定制复杂组件,    //   但缺点是实现复杂,本实例采用的是方法2.    //itemA1->setData(false,Qt::CheckStateRole);    itemA1->setData(false, Qt::DisplayRole);    itemB1->setData("Delphi", Qt::DisplayRole);    itemC1->setData(90, Qt::DisplayRole);    itemD1->setData(QChar('A'), Qt::DisplayRole);    itemA2->setData(true, Qt::DisplayRole);    itemB2->setData("Perl", Qt::DisplayRole);    itemC2->setData(75, Qt::DisplayRole);    itemD2->setData(QChar('B'), Qt::DisplayRole);    root->setChild(0, 0, itemA1);    root->setChild(0, 1, itemB1);    root->setChild(0, 2, itemC1);    root->setChild(0, 3, itemD1);    root->setChild(1, 0, itemA2);    root->setChild(1, 1, itemB2);    root->setChild(1, 2, itemC2);    root->setChild(1, 3, itemD2);}void Widget::onCheckBoxHeaderClicked(bool state){    for(int i=0; i< m_model.rowCount(); i++)    {        QModelIndex index = m_model.index(i, 0, QModelIndex());        m_model.setData(index, state, Qt::DisplayRole);    }}Widget::~Widget(){}

//CheckBoxHeaderView.h

#ifndef CHECKBOXHEADERVIEW_H#define CHECKBOXHEADERVIEW_H#include <QHeaderView>class CheckBoxHeaderView : public QHeaderView{    Q_OBJECT    bool m_isChecked;    static const int CHECTBOXCOLUMNTIDNEX = 0; //要添加复选框的标题栏索引号    void setCheckboxState(bool state);signals:    void checkBoxClicked(bool state); //复选框状态变更时发送信号protected:    void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;    void mousePressEvent(QMouseEvent *evt);public:    explicit CheckBoxHeaderView(Qt::Orientation orientation, QWidget* parent = NULL);};#endif // CHECKBOXHEADERVIEW_H

//CheckBoxHeaderView.cpp

#include "CheckBoxHeaderView.h"#include <QPainter>#include <QMouseEvent>CheckBoxHeaderView::CheckBoxHeaderView(Qt::Orientation orientation, QWidget *parent)        : QHeaderView(orientation, parent){    m_isChecked = false;}void CheckBoxHeaderView::setCheckboxState(bool state){    if(m_isChecked != state)    {        m_isChecked = state;        emit checkBoxClicked(m_isChecked); //通知复选框的状态己变更    }}void CheckBoxHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const{    painter->save();    QHeaderView::paintSection(painter, rect, logicalIndex);    painter->restore();    if(logicalIndex == CHECTBOXCOLUMNTIDNEX)    {        QStyleOptionButton option;        //设置复选框所需的参数        QRect checkBoxRect = this->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option);        option.rect = QRect(rect.x()+5, rect.y()+rect.height()/2 - checkBoxRect.height()/2,                            checkBoxRect.width(), checkBoxRect.height());        option.state = m_isChecked ? QStyle::State_On : QStyle::State_Off;        option.state |= QStyle::State_Enabled | QStyle::State_Active;        //绘制复选框        this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);    }}void CheckBoxHeaderView::mousePressEvent(QMouseEvent *evt){    int indexClicked = logicalIndexAt(evt->pos());    if(indexClicked == CHECTBOXCOLUMNTIDNEX)    {        //获取复选框的大小        int checkBoxWidth = style()->pixelMetric(QStyle::PM_IndicatorWidth);        int checkBoxHeight = style()->pixelMetric(QStyle::PM_IndicatorHeight);        //计算复选框的位置和范围        QRect vrect = QRect(rect().x() + 5,                            rect().y() + rect().height() /2 - checkBoxHeight /2 ,                            checkBoxWidth,                            checkBoxHeight);        //判断当前鼠标是否落在复选框里        if(vrect.contains(evt->pos()))        {            setCheckboxState(!m_isChecked);            viewport()->update(); //或 emit updateSection(CHECTBOXCOLUMNTIDNEX);        }    }    QHeaderView::mousePressEvent(evt);}

//CustomizedItemDelegate.h

#ifndef _CUSTOMIZEDITEMDELEGATE_H_#define _CUSTOMIZEDITEMDELEGATE_H_#include <QItemDelegate>#include <QModelIndex>class CustomizedItemDelegate : public QItemDelegate{    Q_OBJECT    static QRect CheckBoxRect(const QStyleOptionViewItem &viewItemStyleOptions);public:    explicit CustomizedItemDelegate(QObject* parent = 0);    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;    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);};#endif // _CUSTOMIZEDITEMDELEGATE_H_

//CustomizedItemDelegate.cpp

#include "CustomizedItemDelegate.h"#include <QCheckBox>#include <QCombobox>#include <QMouseEvent>#include <QApplication>#include <QPainter>#include <QTextOption>#include <QDebug>CustomizedItemDelegate::CustomizedItemDelegate(QObject *parent):QItemDelegate(parent){}QWidget *CustomizedItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const{    QWidget* ret = NULL;    if(index.data().type() == QVariant::Char)    {        QComboBox* cb = new QComboBox(parent);        cb->addItem("A");        cb->addItem("B");        cb->addItem("C");        cb->addItem("D");        ret = cb;    }    else    {        ret = QItemDelegate::createEditor(parent, option, index);    }    return ret;}void CustomizedItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const{    Q_UNUSED(index);    editor->setGeometry(option.rect);}void CustomizedItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const{    if(index.data().type() == QVariant::Char)    {        QComboBox* cb = dynamic_cast<QComboBox*>(editor);        if(cb != NULL)        {            for (int i=0; i<cb->count(); i++)            {                if(cb->itemText(i) == index.data().toString())                {                    cb->setCurrentIndex(i);                    break;

上一篇:ThreadLocal详解(实现多线程同步访问变量)
下一篇:Openwebrtc

相关文章

相关评论