Алексей Внуков
July 26, 2019, 3:31 a.m.

QML Model & C++Model

qml, qt, model

Доброго времни суток! есть модель на C++,которая берет данные из sqlite базы. в файле QML есть listview, в который должны загружаться данные, с листом очень много действий и в такой ситуации не удобно работать с С++ моделью, поскольку нужно регулярно делать апдейт модели данные в делегатах перезатираются что сильно затрудняет работу, а из самой модели данные нужны только на старте. Собственно вопрос, можно ли при старте програмы С++ модель копировать в QML модель чтоб с ней работать динамично, чтоб только в некоторых ситуациях данные записывались в базу и отобразились только при следующем старте программы.
п.с если не понятно описание задавайте вопросы

2

Do you like it? Share on social networks!

4
Evgenii Legotckoi
  • July 26, 2019, 2:09 p.m.

Добрый день!

А можно код того, как модель C++ регистрируется в QML и как она добавлена в ListView?

    Алексей Внуков
    • July 26, 2019, 2:32 p.m.
    • (edited)

    main.cpp

     PageModel *page_model=new PageModel();
         engine.rootContext()->setContextProperty("page_model",page_model);
    
    

    Pagemodel.h

    class PageModel : public QSqlQueryModel
    {
        Q_OBJECT
    public:
        explicit PageModel(QObject *parent = nullptr);
    
        enum Roles
        {
            idRole= Qt::UserRole+1,
            urlRole,
            nameSiteRole,
            screenRole
        };
    
        Q_INVOKABLE QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
        Q_INVOKABLE QVariantMap get(int idx) const;
    
    signals:
    
    protected:
        QHash<int,QByteArray> roleNames()const;
    
    public slots:
        void updateModel();
        int getId(int row);
    };
    
    

    PageModel.cpp

    PageModel::PageModel(QObject *parent) : QSqlQueryModel (parent)
    {
        this->updateModel();
    }
    
    QVariant PageModel::data(const QModelIndex &index, int role) const
    {
        int columnId = role - Qt::UserRole - 1;
        // Создаём индекс с помощью новоиспечённого ID колонки
        QModelIndex modelIndex = this->index(index.row(), columnId);
    
        /* И с помощью уже метода data() базового класса
         * вытаскиваем данные для таблицы из модели
         * */
        return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
    }
    
    QVariantMap PageModel::get(int idx) const
    {
        QVariantMap map;
        foreach(int k, roleNames().keys()) {
            map[roleNames().value(k)] = data(index(idx, 0), k);
        }
        return map;
    }
    
    QHash<int, QByteArray> PageModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
        roles[idRole]="id";
        roles[urlRole]="url";
        roles[nameSiteRole]="namesite";
        roles[screenRole]="screen";
        return roles;
    }
    
    void PageModel::updateModel()
    {
        this->setQuery("select id, url, namesite, screen from openTabTable");
    }
    
    int PageModel::getId(int row)
    {
        return this->data(this->index(row, 0), idRole).toInt();
    }
    
    

    QML

    import QtQuick 2.12
    import QtQuick.Controls 2.12
    import QtWebView 1.13
    
    Item {
        id: idListView1Form
        width: 400
        height: 700
    
        Rectangle{
            id: rectangleForListView
            y: parent.height * 0.15
            height: parent.height * 0.7
            anchors.left: parent.left
            anchors.right: parent.right
    
            ListView
            {
                id: myListView1
                highlightRangeMode: ListView.StrictlyEnforceRange
                anchors.fill: parent
                orientation : ListView.Horizontal
                snapMode: ListView.NoSnap
                contentX: 100
                contentWidth: 100
                model: page_model
    
                delegate:ItemDelegate
                {
                    id: itemDelegate
                    width : myListView1.width < myListView1.height ? myListView1.width * 0.7 : myListView1.height * 1
                    height: myListView1.width < myListView1.height ? myListView1.width * 1 : myListView1.height * 0.7
                    Rectangle
                    {
    
                        WebView1
                        {
                            id:webView
                        }
    
                        anchors.fill: parent
                        anchors.leftMargin: myListView1.width * 0.06
                        Label
                        {
                            id:site_name
                            anchors.top: parent.top
                            anchors.centerIn: parent
                            text: namesite
                        }
    
                        Rectangle {
                            id: rec1
                            color: "grey"
                            anchors
                            {
                                top:site_name.bottom
                                left: parent.left
                                right:parent.right
                                bottom:parent.bottom
                            }
                            Label
                            {
                                anchors.centerIn: parent
                                text: url
                            }
                        }
    
    
                    }
                    MouseArea
                    {
                        id: ma_click
                        anchors.fill: parent
                        onClicked:
                        {
                            webView.url=url
                            stack.push(webView)
                        }
                    }
                }
            }
        }
    }
    
    
      Evgenii Legotckoi
      • July 26, 2019, 3:10 p.m.
      • The answer was marked as a solution.

      Я не уверен, но думаю. что можно ещё переписать метод setData в QSqlQueryModel, в котором записывать данные в базу данных и сразу делать апдейт модели после записи данных в базу данных. Тогда проблема с перезатиранием данных в делегатах будет уже менее актуальна.

      Также, как вы и сказали, что данные нужны только при старте, то я бы попробовал написать обычную модель данных. в функции main, забирал бы данные из базы данных в вектор, которые бы устанавливал в ту модель. Тогда уже данные не будут так зависимы от базы данных, как было поначалу.

      Ещё можно попробовать с помощью QVariantMap протолкнуть данные до QML и там уже записать в QML модель данных.

      Ещё можно попробовать взять данные из базы данных прямо в QML

      import QtQuick 2.0
      
      Rectangle {
          color: "white"
          width: 200
          height: 100
      
          Text {
              text: "?"
              anchors.horizontalCenter: parent.horizontalCenter
              function findGreetings() {
                  var db = openDatabaseSync("QDeclarativeExampleDB", "1.0", "The Example QML SQL!", 1000000);
      
                  db.transaction(
                      function(tx) {
                          // Create the database if it doesn't already exist
                          tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)');
      
                          // Add (another) greeting row
                          tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]);
      
                          // Show all added greetings
                          var rs = tx.executeSql('SELECT * FROM Greeting');
      
                          var r = ""
                          for (var i = 0; i < rs.rows.length; i++) {
                              r += rs.rows.item(i).salutation + ", " + rs.rows.item(i).salutee + "\n"
                          }
                          text = r
                      }
                  )
              }
              Component.onCompleted: findGreetings()
          }
      }
      

      Тогда манипуляций в C++ делать не нужно будет.

        Алексей Внуков
        • July 26, 2019, 3:59 p.m.

        благодарю, интересное решение

          Comments

          Only authorized users can post comments.
          Please, Log in or Sign up
          • Last comments
          • AK
            April 24, 2025, 12:04 p.m.
            UPD: Переписал логику воспроизведения через стороннюю библиотеку BASS. Там выбрать можно
          • Evgenii Legotckoi
            April 16, 2025, 5:08 p.m.
            Благодарю за отзыв. И вам желаю всяческих успехов!
          • IscanderChe
            April 12, 2025, 5:12 p.m.
            Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
          • AK
            April 1, 2025, 11:41 a.m.
            Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
          • Evgenii Legotckoi
            March 9, 2025, 9:02 p.m.
            К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…