天天看點

Qt模型視圖架構:自定義委托

這裡實作一個委托使用 QSpinBox 來提供編輯功能,主要用于顯示整數的模型。

從 QStyledItemDelegate 子類化委托而不是 QAbstractItemDelegate,因為QStyledItemDelegate 已經實作了 paint() 函數。 

class SpinBoxDelegate : public QStyledItemDelegate
 {
     Q_OBJECT

 public:
     SpinBoxDelegate(QObject *parent = nullptr);

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

     void setEditorData(QWidget *editor, const QModelIndex &index) const override;
     void setModelData(QWidget *editor, QAbstractItemModel *model,
                       const QModelIndex &index) const override;

     void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
                               const QModelIndex &index) const override;
 };
           

提供編輯器

當視圖需要提供一個編輯器時,它會要求委托提供一個适合被修改項目的編輯器小部件。 createEditor() 函數就是用來提供這個小部件的:

QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
                                        const QStyleOptionViewItem &/* option */,
                                        const QModelIndex &/* index */) const
 {
     QSpinBox *editor = new QSpinBox(parent);
     editor->setFrame(false);
     editor->setMinimum(0);
     editor->setMaximum(100);

     return editor;
 }
           

不需要保留指向編輯器小部件的指針,因為視圖負責在不再需要時銷毀它。

可以根據視圖提供的模型索引建立不同的編輯器。例如,如果有一列整數和一列字元串,則可以根據正在編輯的列傳回 QSpinBox 或 QLineEdit。

委托需要提供一個函數來将模型資料複制到編輯器中,setEditorData()就是這個函數。在這個例子中,讀取顯示角色中存儲的資料,并相應地設定了微調框中的值。

void SpinBoxDelegate::setEditorData(QWidget *editor,
                                     const QModelIndex &index) const
 {
     int value = index.model()->data(index, Qt::EditRole).toInt();

     QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
     spinBox->setValue(value);
 }
           

向模型送出資料

當使用者完成編輯時,視圖要求委托通過調用 setModelData() 函數将編輯後的值存儲在模型中。

void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                    const QModelIndex &index) const
 {
     QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
     spinBox->interpretText();
     int value = spinBox->value();

     model->setData(index, value, Qt::EditRole);
 }
           

當視圖完成編輯時,委托類通過發出 closeEditor() 信号通知視圖。該視圖確定編輯器小部件已關閉并銷毀。

更新編輯器的幾何圖形

管理編輯器的幾何圖形是委托的責任。必須在建立編輯器時以及更改視圖中項目的大小或位置時設定幾何圖形。幸運的是,視圖在視圖選項對象中提供了所有必要的幾何資訊。

void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
                                            const QStyleOptionViewItem &option,
                                            const QModelIndex &/* index */) const
 {
     editor->setGeometry(option.rect);
 }
           

彙總

#ifndef SPINBOXDELEGATE_H
#define SPINBOXDELEGATE_H

#include <QStyledItemDelegate>

class SpinBoxDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    SpinBoxDelegate(QObject *parent = nullptr);

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

    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor, QAbstractItemModel *model,
                      const QModelIndex &index) const override;

    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
                              const QModelIndex &index) const override;
};

#endif // SPINBOXDELEGATE_H
           
#include "spinboxdelegate.h"
#include <QSpinBox>
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{

}

QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
                                       const QStyleOptionViewItem &/* option */,
                                       const QModelIndex &/* index */) const
{
    QSpinBox *editor = new QSpinBox(parent);
    editor->setFrame(false);
    editor->setMinimum(0);
    editor->setMaximum(100);

    return editor;
}

void SpinBoxDelegate::setEditorData(QWidget *editor,
                                    const QModelIndex &index) const
{
    int value = index.model()->data(index, Qt::EditRole).toInt();

    QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
    spinBox->setValue(value);
}

void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                   const QModelIndex &index) const
{
    QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
    spinBox->interpretText();
    int value = spinBox->value();

    model->setData(index, value, Qt::EditRole);
}

void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
                                           const QStyleOptionViewItem &option,
                                           const QModelIndex &/* index */) const
{
    editor->setGeometry(option.rect);
}
           
QStandardItemModel * model = new QStandardItemModel;
    model->setColumnCount(2);
    model->setRowCount(2);
    model->setData(model->index(0,0),1);
    model->setData(model->index(0,1),2);
    model->setData(model->index(1,0),3);
    model->setData(model->index(1,1),4);
    QTableView view2;
    view2.setModel(model);
    view2.setItemDelegate(new SpinBoxDelegate);
    view2.show();
           
Qt模型視圖架構:自定義委托