model.rowCount() 不会绑定到 Item 的属性
Posted
技术标签:
【中文标题】model.rowCount() 不会绑定到 Item 的属性【英文标题】:model.rowCount() won't bind to Item's property 【发布时间】:2018-08-07 13:41:21 【问题描述】:我有一个ListView
,它在 Qml 中使用名为 rootModel
的自定义 C++ 模型进行初始化。
该模型继承QAbstractListModel
并将QVector<customType>
定义为私有成员以填充模型。
在我的ApplicationWindow
中,我创建了一个Dialog
,我在其中更改了模型并调用setList()
函数来更新它。这很好用。
我还想将模型的大小连接到ScrollView
的int
属性。此属性将定义RowLayout
的children
。
问题是当我尝试将此属性绑定到模型的大小时,应用程序崩溃了。
仅供参考,模型的所有修改都遵循 Qt 的规则。 rowCount()
是 Q_INVOKABLE
。我也尝试过使用onModelChanged
处理程序,但这不起作用(我在文档中检查了当modelReset()
发出时会发出这个信号,这发生在setList()
到endResetModel()
内
我相信这是一个简单的过程(我已经在我的项目中多次执行了属性绑定)但没有按预期工作。
我引用了我项目的一些示例代码。
//main.qml
ConfiguredChannels
id: configuredList
anchors
left: parent.left
top: devices.bottom
right: tabs.left
bottom: parent.bottom
TabArea
id: tabs
y: toolBar.height
x: parent.width / 8
anchors
top: toolBar.bottom
width: 3 * parent.width / 4
height: 3 * parent.height / 4
countPWM: configuredList.model.rowCount() //This is where I want to bind.
//ConfiguredChannels.qml
id: confChanView
header: confChanHeader
model: ChannelModel
id: rootModel
list: channelList
//TabArea.qml
Item
id: tabAreaRoot
property alias channelsPWM: channelsPWM
property int countPWM
ScrollView
id: scrollPWM
anchors.fill: parent
contentItem: channelsPWM.children
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOn
RowLayout
id: channelsPWM
spacing: 0
Layout.fillHeight: true
Layout.fillWidth: true
Component.onCompleted:
var namesPWM = [];
for (var i=0; i<countPWM; i++)
namesPWM.push("Channel"+(i+1));
createChannels(countPWM, "PWM", channelsPWM, namesPWM);
[编辑 1]
仔细观察后,我意识到在我当前的实现中,即使我正确绑定到模型的大小,我仍然无法按需创建所需数量的RowLayout
的children
(在我更改模型中的Dialog
Configuration.qml
)。
那是因为我把他们的创作放在了RowLayout
的Component.onCompleted
处理程序中。一旦Configuration.qml
第一次在main.qml
内部初始化,这个处理程序的内容就会被执行。之后,对countPWM
的任何其他更改都不会产生影响,因为组件已经完成!如果我在这一点上错了,请纠正我。
基于此,我遵循了另一个实现。我创建了createChannels
的“包装”函数,命名为createStrips(countPWM)
。这样,要正确更新RowLayout
的children
,我必须调用这个函数。
\\Configuration.qml
\\more code
currentModel.setList(newList)
tabs.createStrips(tableModel.count) \\tableModel is used to populate the newList that will be set to the model
newList.clear()
\\more code
\\TabArea.qml
function createStrips(countPWM)
var namesPWM = [];
for (var i=0; i<countPWM; i++)
namesPWM.push("Channel"+(i+1));
createChannels(countPWM, "PWM", channelsPWM, namesPWM);
function createChannels(counter, channelType, channelParent, channelMapping)
if ( channelParent.children.length !== 0)
console.log("destroying");
for ( var j = channelParent.children.length; j > 0 ; j--)
channelParent.children[j-1].destroy();
for (var i=0;i<counter;i++)
var component = Qt.createComponent(channelType+".qml");
if( component.status !== Component.Ready )
if( component.status === Component.Error )
console.debug("Error:"+ component.errorString() );
return; // or maybe throw
var channels =component.createObject(channelParent, "id": channelType+(i+1), "channelText.text": channelMapping[i]);
[编辑 2]
尽管 EDIT 1 中的解决方案有效并为我的 ScrollView
生成了正确的 children
,但我认为这还不够好,我相信最好的实现是将模型的大小更改与对 createStrips(countPWM)
的调用绑定在一起功能。比如:
\\main.qml
ConfiguredChannels
id: configuredList
anchors
left: parent.left
top: devices.bottom
right: tabs.left
bottom: parent.bottom
onModelChanged: tabs.createStrips(model.rowCount) //or an appropriate signal handler defined on C++ side
也许更好的是,将children
创建为自定义qml
信号处理程序,每次更改模型大小时都会发出该信号处理程序。 (我尝试了上面的onModelChanged
,但没有用。可能我错过了在这种情况下发出的信号)
[解决方案]
我遵循了已接受答案的说明以及此link。
我在名为 rowCount
的头文件内的模型定义中添加了 Q_PROPERTY
和 NOTIFY
rowCountChanged
以及信号 void rowCountChanged();
。此外,在我用来更新模型的函数 setList(newList)
中,我在其实现的末尾添加了 emit rowCountChanged();
。最后,我将此信号与 QML 中的函数 createStrips(count)
连接起来。现在,每次更改模型的大小时,我的ScrollView
都会自动更新显示为RowLayout
的孩子的条带。
\\ChannelModel.h
...
Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
...
signals:
void rowCountChanged();
\\ChannelModel.cpp
void ChannelModel::setList(ChannelList *list)
beginResetModel();
...
endRestModel();
emit rowCountChanged();
\\main.qml
Connections
target: configuredList.model
onRowCountChanged: tabs.createStrips(configuredList.model.rowCount)
【问题讨论】:
您是否试图找出导致调试器崩溃的错误?应用程序崩溃的行是什么?什么是错误信息?请提供所有相关代码,包括型号。 糟糕,我忽略了问题中的崩溃部分。请提供您调用rowCount()
的模型的最小示例,如果这是导致您的应用程序崩溃的原因。绑定到Q_INVOKABLE
s 不是真正的绑定,因为没有更改通知。
【参考方案1】:
只有 q-property 允许绑定,在您的情况下,Q_INVOKABLE
不允许,因此您必须创建它,为此我们使用信号 rowsInserted
和 rowsRemoved
,如下所示:
*.h
Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
public:
...
signals:
void rowCountChanged();
*.cpp
//constructor
connect(this, &QAbstractListModel::rowsInserted, this, &YourModel::rowCountChanged);
connect(this, &QAbstractListModel::rowsRemoved, this, &YourModel::rowCountChanged);
*.qml
countPWM: configuredList.model.rowCount // without ()
注意:
我假设当您添加或删除元素时,您正在使用:
beginInsertRows(QModelIndex(), rowCount(), rowCount());
//append data
endInsertRows();
或者:
beginRemoveRows(QModelIndex(), from, to)
// remove
endRemoveRows();
【讨论】:
我听从了您的建议,但应用程序仍然崩溃。在setList()
内部,我确实使用了您提到的信号,前面是 beginResetModel()
,后面是 endResetModel()
。我尝试将这些与rowCountChanged
连接起来,但它们受到保护。
@K.Tsakalis 不是你有选举,而是必须要做的事情,Qt 强制要求,beginXXX 和 endXXX 立即通知,它们不是信号,它们是函数。另一方面,rowCountChanged 是我创建的信号,它不是方法。
@K.Tsakalis rowsInserted 和 rowsRemoved 是信号 doc.qt.io/qt-5/qabstractitemmodel.html#rowsInserted doc.qt.io/qt-5/qabstractitemmodel.html#rowsRemoved
@K.Tsakalis 要了解 beginXXX 和 endXXX 的使用,请检查以下内容:doc.qt.io/qt-5/model-view-programming.html#an-editable-model,我强调 beginXXX 和 endXXX 是强制性的
@K.Tsakalis 可能您的应用程序因错误的实现而崩溃,所以如果您不显示minimal reproducible example 帮助,那将是不可能的。【参考方案2】:
您无法绑定到 Q_INVOKABLE
,因为与更改信号没有关联。
创建一个Q_PROPERTY(count READ rowCount NOTIFY rowCountChanged)
或类似的东西。确保在插入或删除行时发出信号rowCountChanged
。
当然,如果你有一个会更规范
Q_PROPERTY(count READ count NOTIFY countChanged)
int count() return rowCount();
并确保发出countChanged
。
然后你可以绑定到属性count
。
【讨论】:
以上是关于model.rowCount() 不会绑定到 Item 的属性的主要内容,如果未能解决你的问题,请参考以下文章
Apache Zeppelin python到角度绑定不会一直发生,取消绑定会出错
table.dataChanged(index, index).connect(someFunction) 失败
将属性绑定到 Xamarin 中的 ListView,不会更新视图