代码之家  ›  专栏  ›  技术社区  ›  GAVD

从另一个类调用QQMlaApplicationEngine时的TableView和QAbstracTableModel

  •  0
  • GAVD  · 技术社区  · 7 年前

    我在试着做模型 QAbstractTableModel 在cpp中,并连接到qml。

    此代码运行良好。

    MyModel。h类

    #ifndef MYMODEL_H
    #define MYMODEL_H
    
    #include <QAbstractTableModel>
    
    class MyModel : public QAbstractTableModel
    {
        Q_OBJECT
    
    public:
        enum AnimalRoles {
            TypeRole = Qt::UserRole + 1,
            SizeRole
        };
    
        explicit MyModel(QObject *parent = nullptr);
    
        // Basic functionality:
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    
    protected:
        QHash<int, QByteArray> roleNames() const;
    
    private:
        QList<Animal> m_animals;
    };
    
    #endif // MYMODEL_H
    

    MyModel。cpp公司

    #include "MyModel.h"
    #include <QDebug>
    
    MyModel::MyModel(QObject *parent)
        : QAbstractTableModel(parent)
    {
            qDebug() << __FUNCTION__;
            addAnimal(Animal("Wolf", "Medium"));
            addAnimal(Animal("Polar bear", "Large"));
            addAnimal(Animal("Quoll", "Small"));
    
    }
    
    int MyModel::rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent)
        return m_animals.size();
    }
    
    int MyModel::columnCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent)
        return 2;
    }
    
    QVariant MyModel::data(const QModelIndex &index, int role) const
    {
        qDebug() << __FUNCTION__ << index.row() << index.column() << role;
        if (!index.isValid())
            return QVariant();
        const Animal &animal = m_animals[index.row()];
        switch (role) {
        case TypeRole:
            return animal.type();
        case SizeRole:
            return animal.size();
        default:
            break;
        }
    
        return QVariant();
    }
    
    void MyModel::addAnimal(const Animal &animal)
    {
        qDebug() << __FUNCTION__;
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        m_animals << animal;
        endInsertRows();
    }
    
    QHash<int, QByteArray> MyModel::roleNames() const
    {
        qDebug() << __FUNCTION__;
        QHash<int, QByteArray> roles;
        roles[TypeRole] = "type";
        roles[SizeRole] = "size";
        return roles;
    }
    

    主要的cpp公司

    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
            MyModel model;
    
        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("myModel", &model);
        engine.load(QUrl(QStringLiteral("qrc:/resources/qmls/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

    main\u测试。qml公司

    import QtQuick 2.0
    import QtQuick 2.6
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.4
    
    Window {
        id: main_view
        width: 250
        height: 600
        visible: true
    
        ListView {
            id: list_view
            width: 200; height: 250
    
            model: myModel
            delegate: Text { text: "Animal Test: " + type + ", " + size }
        }
    
    
        TableView {
            id: table_view
            objectName: "tableView"
            width: 250; height: 250
            anchors.top:  list_view.bottom
            model: myModel
    
            TableViewColumn {
                id: type_col
                role: "type"
                title: "Type"
                width: 100
            }
            TableViewColumn {
                id: size_col
                role: "size"
                title: "Size"
                width: 100
            }
        }
    
    }
    

    看起来像这样

    enter image description here

    但是,如果我换了主管道。cpp一点,列表视图显示正常,但不是表视图。

    主要的cpp公司

    #include "MainView.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        MainView mainView;
        return app.exec();
    }
    

    主视图。h类

    #ifndef MAINVIEW_H
    #define MAINVIEW_H
    
    #include <QObject>
    #include <QQmlApplicationEngine>
    
    class MainView: public QObject
    {
        Q_OBJECT
    public:
       explicit  MainView(QObject *parent=nullptr);
        void initializeView();
    
    private:
        QQmlApplicationEngine m_engine;
    };
    
    #endif // MAINVIEW_H
    

    主视图。cpp公司

    #include "MainView.h"
    #include "MyModel.h"
    #include <QQmlContext>
    
    MainView::MainView(QObject *parent)
        : QObject(parent)
    {
        initializeView();
    }
    
    void MainView::initializeView()
    {
        MyModel model;
        m_engine.rootContext()->setContextProperty("myModel", &model);
        m_engine.load(QUrl(QStringLiteral("qrc:/resources/qmls/main_test.qml")));
    
    }
    

    看起来像这样。

    enter image description here

    我真的不明白为什么会这样。在第二种情况下,ListView和TableView有什么区别?如何修复,即在第二种情况下显示数据?提前感谢。

    1 回复  |  直到 7 年前
        1
  •  1
  •   eyllanesc Yonghwan Shin    7 年前

    问题出在 initializeView ,model是该范围内的一个局部变量,当函数完成执行时,将从内存中删除每个局部变量。在第一种情况下,模型将在应用程序关闭时消除,在第二种情况下,模型将在 初始化视图 在显示窗口时,有两种可能的解决方案:

    • 创建指针并管理传递到的内存 MainView 作为家长,以便他将其从内存中删除(最后一个是 QObject s) :

    void MainView::initializeView()
    {
        MyModel *model = new MyModel(this);
        m_engine.rootContext()->setContextProperty("myModel", model);
        m_engine.load(QUrl(QStringLiteral("qrc:/resources/qmls/main_test.qml")));
    
    }
    
    • 使模型成为类的成员。

    *。h类

    #ifndef MAINVIEW_H
    #define MAINVIEW_H
    
    #include <QObject>
    #include <QQmlApplicationEngine>
    
    class MainView: public QObject
    {
        Q_OBJECT
    public:
       explicit  MainView(QObject *parent=nullptr);
        void initializeView();
    
    private:
        QQmlApplicationEngine m_engine;
        MyModel model{this};
    };
    
    #endif // MAINVIEW_H
    

    *。cpp公司

    ...
    
    void MainView::initializeView()
    {
        m_engine.rootContext()->setContextProperty("myModel", &model);
        m_engine.load(QUrl(QStringLiteral("qrc:/resources/qmls/main_test.qml")));
    
    }
    

    为了理解这种行为,我添加了更多的印象点:

    MyModel::~MyModel()
    {
        qDebug()<<"destructor";
    }
    

    TableView {
        ...
        Component.onCompleted: {
            console.log("completed table")
            if(!timer.running)
                timer.running = true
        }
    }
    
    ListView {
        ...
        Component.onCompleted: {
            console.log("completed list")
            if(!timer.running)
                timer.running = true
        }
    }
    
    
    Timer {
        id: timer
        interval: 0;
        onTriggered:  console.log(myModel, table_view.model, list_view.model)
    }
    

    我得到以下信息:

    MyModel
    addAnimal
    addAnimal
    addAnimal
    roleNames
    data 0 0 257
    data 0 0 258
    data 1 0 257
    data 1 0 258
    data 2 0 257
    data 2 0 258
    roleNames
    qml: completed list
    data 0 0 257
    data 0 0 258
    qml: completed table
    destructor
    qml: null null null
    

    我们注意到 ListView 管理加载数据,而 TableView 在负载的中间被称为析构函数。

    可能的解释:我认为 列表视图 存储数据并制作副本,仅在模型通知时更新,也应在删除模型时通知以清理数据,这似乎是一个bug。另一方面 表格视图 ,在加载和删除模型时为null,因此会通知它并清理数据。

    进行另一项测试:

    void MainView::initializeView()
    {
        MyModel *model = new MyModel;
        m_engine.rootContext()->setContextProperty("myModel", model);
        m_engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        QTimer::singleShot(1000, model, &MyModel::deleteLater);
    }
    

    可以观察到,这两种方法都正确加载了数据,并且在第二秒钟后模型被销毁,但只收到通知的是 表格视图 因为它是唯一一个清理显示数据的程序,并且 列表视图 没有。

    我的结论是 列表视图 缺陷