qt - model.rowCount() 不会绑定(bind)到 Item 的属性

标签 qt qml scrollview qtquickcontrols2

我有一个 ListView使用名为 rootModel 的自定义 C++ 模型初始化在 Qml 中。
模型继承QAbstractListModel并定义了 QVector<customType>作为填充模型的私有(private)成员。

在我的 ApplicationWindow我创建了一个 Dialog我在其中更改模型并调用 setList()功能来更新它。这工作正常。

我还想将模型的大小连接到 ScrollViewint属性(property)。该属性将定义 childrenRowLayout .

问题是当我尝试将此属性绑定(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)到模型的大小,我仍然无法创建所需数量的 RowLayoutchildren按需(在我更改 Dialog Configuration.qml 中的模型之后)。

那是因为我把他们的创作放在了RowLayoutComponent.onCompleted处理程序。该处理程序的内容将在 Configuration.qml 执行一次。将在 main.qml 内初始化首次。之后,对 countPWM 的任何其他更改因为组件已经完成,所以不会有什么不同!请纠正我如果我在这一点上错了。

基于此,我遵循了另一个实现。我创建了 createChannels 的“包装器”函数, 命名为 createStrips(countPWM) .这样,正确更新 RowLayoutchildren我必须调用这个函数。
\\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不是,所以你必须创建它,为此我们使用信号 rowsInsertedrowsRemoved如下所示:

*.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/

相关文章:

Qt 安装程序框架 :How to specify the desktop shortcut icon?

Android - Listview 不在 ScrollView 下滚动

android - 如何查看我想在Android Studio Activity 上添加的更多内容,当用户向上滚动时可以查看?

c++ - Qt QML - 无法分配给不存在的属性 "onClicked"

c++ - 访问 QSharedPointer 对象时出现段错误

qml - 是否可以从 C++ 访问 QML anchor ?

c++ - QML 与 CPP 交互 : property double results in NaN

Android onScrollChanged() 未被调用

python - 数学文本解析器 : Fit output to figsize

qt - QML 新手需要帮助从 C++ 中访问 Item 属性