我有一个 ListView
使用名为 rootModel
的自定义 C++ 模型初始化在 Qml 中。
模型继承QAbstractListModel
并定义了 QVector<customType>
作为填充模型的私有(private)成员。
在我的 ApplicationWindow
我创建了一个 Dialog
我在其中更改模型并调用 setList()
功能来更新它。这工作正常。
我还想将模型的大小连接到 ScrollView
的int
属性(property)。该属性将定义 children
的 RowLayout
.
问题是当我尝试将此属性绑定(bind)到模型的大小时,应用程序会崩溃。
仅供引用,模型的所有修改都遵循 Qt 的规则。 rowCount()
是 Q_INVOKABLE
.我也尝试过使用 onModelChanged
处理程序,但这不起作用(我在文档中检查了该信号是在发出 modelReset()
时发出的,这发生在 setList()
到 endResetModel()
内
我相信这是一个简单的过程(在我的项目中已经多次执行属性绑定(bind)),但没有按预期工作。
我引用了我项目的一些示例代码。
//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]
仔细观察后,我意识到在我当前的实现中,即使我正确绑定(bind)到模型的大小,我仍然无法创建所需数量的
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 中的解决方案有效并产生了正确的
children
对于我的ScrollView
我认为这还不够好,我相信最好的实现是将模型的大小更改与对 createStrips(countPWM)
的调用绑定(bind)。功能。就像是:\\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 .
我添加了
Q_PROPERTY
到我的模型在名为 rowCount
的头文件中的定义与 NOTIFY
rowCountChanged
以及信号void rowCountChanged();
.此外,在函数内部 setList(newList)
我用它来更新模型,我在其实现的最后添加了 emit rowCountChanged();
.最后,我将此信号与我的函数 createStrips(count)
连接起来在 QML 中。现在每次更改模型的大小时,我的ScrollView
将自动更新显示为 RowLayout
的 strip 的 children 。\\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 属性允许绑定(bind),在您的情况下为 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();
关于qt - model.rowCount() 不会绑定(bind)到 Item 的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51728264/