滚动

时间:2017-02-07 21:08:39

标签: c++ qt qml qtquick2 qtquickcontrols

我在里面有listview的滚动视图:

ScrollView{
    anchors.fill: parent
    ListView{
        id: lvCommitsBranch
        model: git.getCommitsBranch();
        clip: true
        delegate: Rectangle {
            height: 100
            width: parent.width
            Text {
                anchors.left: parent.left
                font.bold: true
                text:model.author
                id:txtName
            }
            Text{
                anchors.left: parent.left
                anchors.top:txtName.bottom
                font.pixelSize: 10
                text:model.email
                id: txtEmail
            }
            Text {
                anchors.left: parent.left
                anchors.top:txtEmail.bottom
                text: model.message + ' ' + model.hash
                id: txtMsg
            }
            MouseArea{
                anchors.fill: parent
                onClicked: {
                    lvCommitsBranch.currentIndex = index;
                    console.log('Msg: ' + model.message);
                    console.log('Hash: ' + model.hash);
                }
                acceptedButtons: Qt.LeftButton | Qt.RightButton
            }
        }
    }
}

问题在于,当我滚动某些项目时会消失(每次都是随机的,有时我必须快速滚动但不总是)。

enter image description here

当我点击尚未消失的项目时,我会在所有模型的属性上获得undefined。当Mousearea的onclick被触发时,它会打印以下内容:

  

qml:Msg:undefined

     

qml:Hash:undefined

我从我的git自定义组件返回的方法(QAbstractListModel)中获取模型信息。

这是我的QAbstractListModel:

头:

class CommitsBranch : public QAbstractListModel
{
    Q_OBJECT
public:
    enum Roles {
        AuthorRole,
        EMailRole,
        MsgRole,
        DateRole,
        HashRole
    };
    explicit CommitsBranch(QObject *parent = 0);
    CommitsBranch(Repository *repo);
public:
    virtual int rowCount(const QModelIndex &parent) const override;
    virtual QVariant data(const QModelIndex &index, int role) const override;
protected:
    // return the roles mapping to be used by QML
    virtual QHash<int, QByteArray> roleNames() const override;
private:
    QList<Commit> m_data;
    QHash<int, QByteArray> m_roleNames;

};

.cpp的:

CommitsBranch::CommitsBranch(QObject *parent)
    : QAbstractListModel(parent)
{
}

CommitsBranch::CommitsBranch(Repository *repo)
{
    m_roleNames[AuthorRole] = "author";
    m_roleNames[EMailRole] = "email";
    m_roleNames[MsgRole] = "message";
    m_roleNames[DateRole] = "date";
    m_roleNames[HashRole] = "hash";

    /*
    here we append the m_data (QList) Items using libgit2 methods
    */

}

int CommitsBranch::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_data.count();
}

QVariant CommitsBranch::data(const QModelIndex &index, int role) const
{    
    // this function returns the required data
}

QHash<int, QByteArray> CommitsBranch::roleNames() const
{
    return m_roleNames;
}

git只是一个继承自QObject的类,它有以下方法:

Q_INVOKABLE QObject* getCommitsBranch();
QObject *Git::getCommitsBranch()
{
    CommitsBranch* files = new CommitsBranch(repo.data());
    return files;
}

如果没有scrollview,我会得到相同的行为。

编辑: 如果我使用大量提交的存储库(列表视图中有更多行),即使增加cacheBuffer也无济于事,如果我快速滚动,所有项目都将消失。

1 个答案:

答案 0 :(得分:3)

这里的问题是,默认情况下,如果你返回一个QObject *,它会将所有权转移到QML。

http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership

  

此规则的例外情况是从一个QObject返回时   显式C ++方法调用:在这种情况下,QML引擎假定   除非对象的所有权具有,否则对象的所有权   显式设置为通过调用保留C ++   QQmlEngine :: setObjectOwnership()与QQmlEngine :: CppOwnership   指定。

您必须手动设置返回的QObject *所有权,因此它不会被QML引擎销毁:

QObject *Git::getCommitsBranch()
{
    CommitsBranch* files = new CommitsBranch(repo.data());

    QQmlEngine::setObjectOwnership(files, QQmlEngine::CppOwnership)

    return files;
}

请注意,由于永远不会删除CommitsBranch对象,因此会出现内存泄漏。但至少你的QML项目不应该消失了!

编辑:正如所建议你可以这样做以避免内存泄漏:

// CommitsBranch Constructor
CommitsBranch::CommitsBranch(Repository *repo, QObject *parent) :
    QAbstractListModel(parent) { /*stuff*/ }

QObject *Git::getCommitsBranch()
{
    // Setting ownership is not necessary if you pass the parent to the QAbstractListModel
    CommitsBranch* commits = new CommitsBranch(repo.data(), this);

    return files;
}