qt - model.rowCount() 不会绑定到 Item 的属性
问题描述
我有一个用Qml 中ListView
命名的自定义 C++ 模型初始化的。rootModel
模型继承QAbstractListModel
并将 a 定义QVector<customType>
为私有成员以填充模型。
在我的中,我ApplicationWindow
创建了一个Dialog
我更改模型并调用setList()
函数来更新它的函数。这工作正常。
我还想将模型的大小连接到 aScrollView
的int
属性。该属性将定义children
a 的RowLayout
。
问题是当我尝试将此属性绑定到模型的大小时,应用程序会崩溃。
仅供参考,模型的所有修改都遵循 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
'sComponent.onCompleted
处理程序中。Configuration.qml
一旦第一次在里面初始化,这个处理程序的内容就会被执行main.qml
。之后,对 的任何其他更改countPWM
都不会产生影响,因为组件已经完成!如果我在这一点上错了,请纠正我。
基于此,我遵循了另一个实现。我创建了一个createChannels
名为的“包装器”函数createStrips(countPWM)
。这样,要正确更新RowLayout
'schildren
我必须调用此函数。
\\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]children
虽然 EDIT 1 中的解决方案有效并为我提供
了正确的解决方案,但ScrollView
我认为这还不够好,我相信最好的实现是将模型的大小更改与对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
上述方法但没有用。可能我错过了在这种情况下发出的信号)
[解决方案]
我按照已接受答案的说明以及此链接进行操作。
我在以 the和 signal命名的头文件中添加了一个Q_PROPERTY
到我的模型定义中。此外,在我用来更新模型的函数中,我在其实现的最后添加了. 最后,我将此信号与我在 QML 中的函数连接起来。现在每次更改模型的大小时,我都会自动更新显示为 的子项的条带。rowCount
NOTIFY
rowCountChanged
void rowCountChanged();
setList(newList)
emit rowCountChanged();
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)
}
解决方案
只有 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();
推荐阅读
- java - 如何从 JAVA API 运行桌面应用程序(TPT)?
- gradle - JUnit 测试无法正确加载 fop 0.20.5 所需的 xercesImpl jar
- android - Kotlin 中的赋值变量无法正确解析
- javascript - js中加一个+是什么意思?
- security - 删除 SSRS 中用户定义的安全角色
- javascript - Webpack 文件加载器输出 [object Module]
- rust - 在 Rust 中居中动态字符串?
- php - 如何获得超过 13 个数字的 EAN 被排除(PHP)
- python-3.x - 为什么主线程等待后台线程完成
- flutter - LocalServer 与 Flutter 应用程序之间的连接