QDataWidgetMapper 用来将 QAbstractItemModel 中的数据 用一组 QWidget派生类(QLineEdit、QSpinBox等)来显示。是一种基于 record 或 form-based 的方式,可以显示或修改model中的一行或一列。
使用QDataWidgetMapper 是使用还是很方便的。只要记住核心是关联一个model和一组widget
- 创建 QDataWidgetMapper 对象
- 关联 model
- 关联 widgets,并创建其与model中section的映射
- 定位到某个 record
mapper->setModel(model);
mapper->addMapping(mySpinBox, 0);
mapper->addMapping(myLineEdit, 1);
mapper->addMapping(myCountryChooser, 2);
mapper->toFirst();思考void addMapping (QWidget * widget, int section )
void addMapping (QWidget * widget, int section, const QByteArray & propertyName )
我们知道model有统一的数据接口,但widget不像view那样有统一的接口。二者的数据是怎么联系的呢。
model 和 widget 关联,widget的方法不是统一的,它怎么去调用 widget 相应的方法呢?比如,
- widget是QLineEdit,怎么找到并调用的 setText(),
- widget是QSpinBox,它怎么找到并调用的 setValue() 函数
第二个函数中的 propertyName 又是什么东西。
其实 Manual 中说明的很详细了,
- Every time the current index changes, each widget is updated with data from the model via the property specified when its mapping was made. If the user edits the contents of a widget, the changes are read using the same property and written back to the model. By default, each widget's user property is used to transfer data between the model and the widget. Since Qt 4.3, an additional addMapping() function enables a named property to be used instead of the default user property.
但一开始没看 Manual(不可容忍的错误做法),于是绕了个大弯,看源码吧:
源码数据流向: model ==> widgetvoid QDataWidgetMapperPrivate::populate(WidgetMapper &m){
if (m.widget.isNull())
return;
m.currentIndex = indexAt(m.section);
if (m.property.isEmpty())
delegate->setEditorData(m.widget, m.currentIndex);
else
m.widget->setProperty(m.property, m.currentIndex.data(Qt::EditRole));
}
-
m.widget 是我们设置的widget的智能指针 QPointer<QWidget>
- m.currentIndex 是 model 当前的 modelindex,注意类型是:QPersistentModelIndex
- QPersistentModelIndex 与 QModelIndex 可以自由转换。前者可以保存备用,后者获取后要立即使用
- m.property 是前面提到的 propertyName
现在问题就很明朗了:
- 如果我们使用的是第一个 addMapping(即propertyName为空),负责设置 widget 内容的是QItemDelegate::setEditorData
- 继续看setEditorData的Manual可知,它使用的Widget的 User 属性
- 如果我们使用的是第二个 addMapping,后面的propertyName 就是我们的Widget中定义的一个Property(使用 Q_PROPERTY 宏)
先前看 Qt 属性系统时,始终看不懂 User Property 是做什么用的。看到这儿才突然理解了...
- QLineEdit类定义的 USER 属性
{
Q_OBJECT
...
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true)
...
- QSpinBox类定义的 USER 属性
{
Q_OBJECT
...
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true)
...数据流向:widget ==> modelbool QDataWidgetMapperPrivate::commit(const WidgetMapper &m)
{
if (m.widget.isNull())
return true; // just ignore
if (!m.currentIndex.isValid())
return false;
// Create copy to avoid passing the widget mappers data
QModelIndex idx = m.currentIndex;
if (m.property.isEmpty())
delegate->setModelData(m.widget, model, idx);
else
model->setData(idx, m.widget->property(m.property), Qt::EditRole);
return true;
}
代码分析和前面的一样,只不过是读写翻了一下。
参考-
http://doc.qt.nokia.com/4.2/qdatawidgetmapper.html
-
http://doc.qt.nokia.com/4.7/itemviews-simplewidgetmapper.html
-
http://doc.qt.nokia.com/qq/qq21-datawidgetmapper.html