1. 程式人生 > >Qt Model/View理解(三)---橋樑Delegate

Qt Model/View理解(三)---橋樑Delegate

上兩節中介紹瞭如何構造model,並與資料關聯,在不同的顯示控制元件中展示資料的方式。都是以只讀方式讀取資料,然後顯示出來,沒有對資料來源進行寫操作。今天將以第2節為基礎,實現修改並顯示資料來源的功能。這裡開始引入了代理(Delegate)的概念。

代理在模型和檢視中間橋樑的作用,它可以渲染資料項,並通知模型和檢視進行資料更新。

實現修改第2節中的資料項的思路:

1.雙擊任何一個空白處,彈出一個LineEdit;

2.獲取原先顯示的資料到LineEdit控制元件中,編輯資料;

3.將新的資料回寫到模型和二維陣列中,檢視和模型自動就會關聯並顯示新的資料。

下面開始寫程式碼:

一、QAbstractItemDelegate是模型/檢視框架中代理的基類。預設的代理實現由QStyledItemDelegate類提供。我們實現一個類LineEditDelegate,繼承自QStyledItemDelegate。

class LineEditDeleget : public QStyledItemDelegate
{
public:
    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;
};
//建立編輯器,這些編輯器是一些控制元件,如Label,LineEdit,Combox等
QWidget *LineEditDeleget::createEditor(QWidget * parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
{
    QLineEdit *line = new QLineEdit(parent);
    return line;
}

//從model中取出資料,放到編輯器中
void	LineEditDeleget::setEditorData(QWidget * editor, const QModelIndex & index) const
{
    QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
    QString str = index.model()->data(index,Qt::DisplayRole).toString();//獲取model中的資料,角色為DisplayRole
    lineEdit->setText(str);
}

//將編輯器中的資料更新到model中
void	LineEditDeleget::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
    QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
    model->setData(index,lineEdit->text(),Qt::EditRole);
}

我們通過過載了3個函式,createEditor函式中建立了一個LineEdit控制元件,當雙擊表格項時該LineEdit控制元件就會顯示出來;接下來,我們要把原先model中顯示的資料放到LineEdit控制元件中,主要是通過index下標來獲取值,由setEditorData函式實現。最後,修改的新資料,目前只是存在於LineEdit控制元件上,並沒有寫入model中。通過setModelData函式,將對應的index下標的model資料進行更新。注意,此時修改資料時的角色型別是Qt::EditRole。

二、代理類更新了model的資料,然而,model類中必須要做出相應的處理才能真正實現資料更新。TableModel類中要新增2個新的介面flags和setData。最後如下:

class TableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    TableModel(QObject *parent = 0);
    ~TableModel();
    //QAbstractTableModel 中3個必須重新實現的虛擬函式
    int	rowCount(const QModelIndex & parent = QModelIndex()) const;
    int	columnCount(const QModelIndex & parent = QModelIndex()) const;
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;

    Qt::ItemFlags flags(const QModelIndex & index) const;
    bool setData(const QModelIndex & index, const QVariant & value, int role);

private:
    int num[ROW][COL];
    int nn;
};
//可編輯表格新增函式
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags flags = QAbstractItemModel::flags(index);
    flags |= Qt::ItemIsEditable;
    return flags;
}

bool TableModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    if (index.isValid() && role == Qt::EditRole)
     {
         num[index.row()][index.column()] = value.toInt();
         emit dataChanged(index, index);
         return true;
     }
     return false;
}

flags函式作用主要表示當前的model並不是一個只讀的,還有可編輯的功能。當代理類修改了model中的資料時,model類會呼叫setData根據修改資料時的角色進行判斷,修改二維陣列中的值,併發送資料改變的訊號,以此完成資料的更新。