26.QT-模型視圖之自定義委託

      在上一章學習 25.QT-模型視圖 後,本章接着學習視圖委託html


視圖委託(Delegate)簡介設計模式

因爲模型負責組織數據,而視圖負責顯示數據,因此當用戶想修改顯示的數據時,就要經過視圖中的委託來完成編輯器

視圖委託相似於傳統的MVC設計模式裏的Controller(控制器)角色函數

  • Model(模型) - 負責數據組織
  • View(視圖) - 負責數據顯示
  • Controller(控制器) - 負責用戶輸入,並處理數據

 

 

初探自定義委託類 
post

  • 委託屬於視圖的子功能
  • 視圖主要負責組織具體數據項的顯示方式(是列表方式,仍是樹形方式,仍是表格方式)
  • 委託主要負責具體數據項的顯示和編輯,好比用戶須要編輯某個數據時,則須要彈出編輯框
  • 視圖能夠經過 itemDelegate() ,setItemDelegate ( )成員函數來 得到/設置當前委託對象
  • QAbstractItemDelegate類是全部委託的父類,用來 負責提供通用接口
  • 在模型視圖中,會默認提供一個QStyledItemDelegate類,供用戶編輯數據
  • 也能夠經過繼承QItemDelegate父類,實現自定義委託功能

 

QAbstractItemDelegate類中的關鍵虛函數學習

QWidget * createEditor( QWidget * parent, QStyleOptionViewItem & option, QModelIndex & index ) ;
//建立編輯器,並返回該編輯器, option包含了該數據項的具體信息(好比:數據項窗口大小,字體格式,對齊方式,圖標位於字體的哪一個位置等)、index 包含了該數據項的內容(好比:text信息,背景色等)

void updateEditorGeometry ( QWidget * editor, QStyleOptionViewItem & option, QModelIndex &index );
//該函數裏,能夠經過editor->setGeometry()更新編輯組件大小,保證editor顯示的位置及大小
//大小能夠經過option.rect獲取數據項窗口大小

void setEditorData ( QWidget * editor, const QModelIndex & index );
//經過索引值,將模型裏的數據提取到編輯器內容裏

void  setModelData ( QWidget * editor, QAbstractItemModel * model, QModelIndex & index );
//經過索引值, 根據editor 的數據更新model的數據。

void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) ;
//複製繪畫數據項的顯示和編輯

QAbstractItemDelegate類中的關鍵信號字體

void  closeEditor ( QWidget * editor, QAbstractItemDelegate::EndEditHint hint = NoHint );
//當用戶關閉編輯器後,就會發出這個信號。
// hint 參數用來指定當用戶完成編輯後,應該顯示什麼標記,用來提示用戶已完成編輯

void   commitData ( QWidget * editor ) ;
//當完成編輯數據後,發送該信號,表示有新數據提交到模型中

 

咱們以編輯某個數據項爲例:ui

  • 視圖首先會調用createEditor()函數生成編輯器
  • 調用updateEditorGeometry()函數設置編輯器組件大小
  • 調用setEditorData()函數,將模型裏的數據提取到編輯器中
  • 等待用戶編輯... ...
  • 當用戶編輯完成後, 系統將會發送commitData信號函數
  • 而後調用setModelData()函數,設置模型數據,以及setEditorData()函數,更新編輯器
  • 視圖最後發送closeEditor()信號函數,表示已關閉編輯器

 

接下來,咱們重寫上面函數,來自定義一個QCostomizedDelegate委託類url

效果以下spa

 

QCustomizedDelegate.h:

#ifndef QCUSTOMIZEDDELEGATE_H

#define QCUSTOMIZEDDELEGATE_H

#include <QItemDelegate>

#include <QtGui>

class QCustomizedDelegate : public QItemDelegate

{

    Q_OBJECT

public:

    explicit QCustomizedDelegate(QObject *parent = 0);

    QWidget *  createEditor( QWidget * parent, 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       updateEditorGeometry( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const;

 

};

#endif // QCUSTOMIZEDDELEGATE_H

QCustomizedDelegate.cpp:

#include "QCustomizedDelegate.h"
QCustomizedDelegate::QCustomizedDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget* QCustomizedDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(index.column()==1) //第1列 班級 { QComboBox *Cbox = new QComboBox(parent); Cbox->addItems(QStringList()<<"1班"<<"2班"<<"3班"<<"4班"<<"5班"); return Cbox; } else if(index.column()==2) //第2列 分數 { QSpinBox *Sbox = new QSpinBox(parent); Sbox->setRange(0,150); return Sbox; } return QItemDelegate::createEditor(parent, option, index); //第0列,則選擇默認編輯器 } void QCustomizedDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const { if(index.column()==1) //第1列 班級 { QComboBox *Cbox = dynamic_cast<QComboBox*>(editor); Cbox->setCurrentIndex(Cbox->findText( index.data(Qt::DisplayRole).toString())); } else if(index.column()==2) //第2列 分數 { QSpinBox *Sbox = dynamic_cast<QSpinBox*>(editor); Sbox->setValue(index.data(Qt::DisplayRole).toInt()); } else QItemDelegate::setEditorData(editor, index); } void QCustomizedDelegate::setModelData ( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const { if(index.column()==1) //第1列 班級 { QComboBox *Cbox = dynamic_cast<QComboBox*>(editor); model->setData(index,Cbox->currentText(),Qt::DisplayRole); } else if(index.column()==2) //第2列 分數 { QSpinBox *Sbox = dynamic_cast<QSpinBox*>(editor); model->setData(index,Sbox->value(),Qt::DisplayRole); } else QItemDelegate::setModelData(editor, model, index); } void QCustomizedDelegate::updateEditorGeometry ( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const { editor->setGeometry(option.rect); }

而後,再經過視圖的setItemDelegate(QAbstractItemDelegate * delegate )成員函數設置咱們自定義的委託類對象便可

 

深刻自定義委託類

以前咱們寫的自定義委託,每次都須要雙擊某個數據項,才能彈出編輯器

那如何讓委託一直呈如今視圖顯示上呢?

步驟以下:

  • 重寫委託類的paint成員函數
  • 在paint()中,經過QApplication::style()->drawControl()來自定義數據顯示方式,好比繪製按鈕
  • 重寫委託類的editorEvent成員函數
  • 在editorEvent中處理交互事件,好比判斷鼠標是否雙擊,以及更改模型數據等

 

其中QApplication::style()->drawControl()函數參數以下所示:

QApplication::style()->drawControl (ControlElement element,
                     constQStyleOption
* option,
                      QPainter *painter, const QWidget * widget = 0 ) ; //繪畫組件 // element: 元素,用來指定控件樣式,好比: QStyle::CE_CheckBox 表示繪畫的widget是一個text文本的複選框 // option:選項,用來繪製控件所需的全部參數好比option.rect(設置組件大小位置), option.state(設置組件狀態)
//其中option. state成員值常見的有:   QStyle::State_Enabled //表示該組件是激活的,能夠被用戶操做   QStyle::State_On //表示該組件樣式是被選上的   QStyle::State_Off //表示該組件樣式是未被選中的   QStyle::State_MouseOver //表示表示該組件樣式是:鼠標停留在組件上面的樣子   QStyle::State_Sunken //表示該組件樣式是:鼠標按壓下的組件樣子   QStyle::State_HasEditFocus //表示該組件是否有編輯焦點 // painter:誰來繪畫 // widget = 0:若是該widget爲0,則表示使用QT自帶的風格

 

示例-自定義一個QCostomizedDelegate委託類

效果以下

 

代碼以下

QCustomizedDelegate.h:

#ifndef QCUSTOMIZEDDELEGATE_H
#define QCUSTOMIZEDDELEGATE_H

#include <QItemDelegate>
#include <QtGui>
#include "ProgressBar.h"

class QCustomizedDelegate : public QItemDelegate
{
    Q_OBJECT
    //m_bar:溫度臺的當前溫度進度條
    QScopedPointer<QProgressBar>  m_bar ;

public:
    explicit QCustomizedDelegate(QObject *parent = 0);
    void       paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    bool       editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index );

};

#endif // QCUSTOMIZEDDELEGATE_H

QCustomizedDelegate.cpp:

#include "QCustomizedDelegate.h"
#include "ProgressBar.h"

QCustomizedDelegate::QCustomizedDelegate(QObject *parent) :
    QItemDelegate(parent),
    m_bar(new QProgressBar())
{
     m_bar->setStyleSheet(qApp->styleSheet());       //設置風格            
}

void  QCustomizedDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
    if(index.column()==1 && index.data().type() == QVariant::Int)     //判斷列數,並判斷索引值是否int型(溫度是經過int型值表示的)
    {
        int radio=14;
        int top = option.rect.top() + radio;
        int left = option.rect.left() + radio;
        int width = option.rect.width() - 2 * radio;
        int height = option.rect.height() - 2 * radio;

        QStyleOptionProgressBar bar;                   //設置參數
        bar.rect.setRect(left, top, width, height); 
        bar.state  = QStyle::State_Enabled;
        bar.progress = index.data().toInt();
        bar.maximum = 100;
        bar.minimum = 0;
        bar.textVisible = true;
        bar.text    =   QString("當前溫度:%1°").arg(bar.progress);
        bar.textAlignment = Qt::AlignCenter;

        QApplication::style()->drawControl(QStyle::CE_ProgressBar,&bar,painter, m_bar.data());
    }
    else
    {
        QItemDelegate::paint(painter,option,index);
    }
}

bool    QCustomizedDelegate::editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index )
{
    if(event->type() == QEvent::MouseButtonDblClick)     //禁止雙擊編輯
    {
            return true;
    }
    return QItemDelegate::editorEvent(event,model,option,index);
}
相關文章
相關標籤/搜索