Qt自定义代理与实例
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. 扩展
其他一些关于模型的细节,大家可以看看我之前的文章