1. 代理的定義
代理(Delegate)就是在視圖組件上為編輯數據提供編輯器,如在表格組件中編輯一個單元格的數據時,缺省是使用一個QLineEdit編輯框。代理負責從數據模型獲取相應的數據,然后顯示在編輯器里,修改數據后,又將其保存到數據模型中。
QAbstractItemDelegate是所有代理類的基類,作為抽象類,它不能直接使用。它的一個子類QStyledItemDelegate,是Qt的視圖組件缺省使用的代理類。
對於一些特殊的數據編輯需求,例如只允許輸入整型數,使用一個QSpinBox作為代理組件更恰當,從列表中選擇數據時使用一個QComboBox作為代理組件更好。這時,就可以從QStyledItemDelegate繼承創建自定義代理類
2. 自定義代理的功能
當我們導入數據文件進行編輯時,QTableView組件為每個單元格提供的是缺省的代理編輯組件,就是一個QLineEdit組件。
在編輯框里可以輸入任何數據,所以比較通用。但是有些情況下,希望根據數據的類型限定使用不同的編輯組件,例如第1列我們要求是整數,使用QSpinBox作為編輯組件更合適
3. 自定義代理類的基本要求
不管從QStyledItemDelegate還是QItemDelegate繼承設計自定義代理組件,都必須實現如下的4個函數:
- createEditor()函數創建用於編輯模型數據的 widget組件,如一個QSpinBox組件,或一個QComboBox 組件;
- setEditorData()函數從數據模型獲取數據,供 widget組件進行編輯;
- setModelData()將 widget上的數據更新到數據模型;
- updateEditorGeometry()用於給widget組件設置一個合適的大小。
4. 實例
4.1 效果演示
我們要實現的就是,弄一個表格,當我們編輯數據的時候,能夠有下圖所示的效果
而不是單獨的文本編輯框,還有下面這種spinbox
4.2 關鍵代碼分析
為了方便起見,我們采用spinbox的代理類來講解具體的代碼
首先要記得,我們得實現4個函數
createEditor() 創建用於編輯模型數據的 widget組件
static string MyBlog = "https://www.cnblogs.com/wanghongyang";
QWidget *SpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &/*option*/,const QModelIndex &/*index*/) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setRange(0,10000);
editor->installEventFilter(const_cast<SpinDelegate*>(this));
return editor;
}
這里創建了一個spinbox組件,設置范圍,安裝過濾器,我們來看看這個過濾器的用法
void QObject::installEventFilter(QObject *filterObj)
在這個對象上安裝一個事件過濾器filterObj
事件篩選器是一個對象,它接收發送到此對象的所有事件。過濾器可以停止事件,也可以將事件轉發給該對象。事件過濾器filterObj通過其eventFilter()函數接收事件。eventFilter()函數必須返回true,如果事件應該被過濾(即停止);否則它必須返回false。
如果在單個對象上安裝多個事件篩選器,最后安裝的篩選器將首先激活。
看到這里const_cast有些不明白,我們再來看看const_cast
const_cast轉換符是用來移除變量的const或volatile限定符
**setEditorData() **從數據模型獲取數據,供 widget組件進行編輯
void SpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
int value =index.model()->data(index).toInt();
QSpinBox *box = static_cast<QSpinBox*>(editor);
box->setValue(value);
}
函數重模型中獲得數據,然后設置數據給組件進行編輯
setModelData() 將 widget上的數據更新到數據模型
void SpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const
{
QSpinBox *box = static_cast<QSpinBox*>(editor);
int value = box->value();
model->setData(index,value);
}
代碼淺顯易懂,不過多贅述
updateEditorGeometry() 給widget組件設置一個合適的大小
void SpinDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
editor->setGeometry(option.rect);
}
接下來我們看看這些函數的具體使用
在main函數中設置代理,通過列的方式
SpinDelegate spinDelegate;
tableView.setItemDelegateForColumn(3,&spinDelegate);
這樣就可以使用自定義代理了
4. 擴展
其他一些關於模型的細節,大家可以看看我之前的文章