Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to fill data Qt Item Model



  • Hi,
    I just want to use Qt/Qml in Android.
    I fallow this video in case of learn Qt and QML talking.

    I want to get items from web page. I create one php file and returning String List. I called this php file in constructor block of OtItemModel which I just created. But When I run the code

    sakinlerListesi.h

    #ifndef SAKINLERLISTESI_H
    #define SAKINLERLISTESI_H
    
    #include <QAbstractListModel>
    #include <QDebug>
    
    //İnternet için
    #include <QNetworkAccessManager>
    #include <QNetworkRequest>
    #include <QNetworkReply>
    
    
    #include <QEventLoop>
    
    
    
    class SakinlerListesi : public QAbstractListModel
    {
        Q_OBJECT
    
    public:
        explicit SakinlerListesi(QObject *parent = nullptr);
    
        enum {
            aciklama
        };
    
        // Basic functionality:
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    
        virtual QHash<int, QByteArray> roleNames() const override;
    
        bool checkInternet();
    
        void sakinAl();
    
    private slots:
    
        void sakinAlCevap(QNetworkReply *reply);
    
    
    
    
    
    private:
        int sayac = 0;    
        QList<QString> donenSakinler;
    };
    
    #endif // SAKINLERLISTESI_H
    
    

    sakinlerListesi.cpp

    #include "sakinlerlistesi.h"
    
    
    
    
    SakinlerListesi::SakinlerListesi(QObject *parent)
        : QAbstractListModel(parent)
    {   
    
       //Below function call the php request
    
    
        sakinAl();
    
       //But unfotunately data donenSakinler.count() is zero in here! I don't know why?
    
    
        //do{}while(sayac<1);
    
    
        qDebug()<<donenSakinler;
    
        qDebug()<<donenSakinler.count();
    
    
    }
    
    
    void SakinlerListesi::sakinAl()
    {
        if(!checkInternet())
        {
           qDebug()<<"İnternet Yok!";
            return;
    
        }
    
    
        QNetworkAccessManager * manager = new QNetworkAccessManager(this);
    
        QUrl url("https://www.mucipilbuga.com/XXX/aaa.php");
    
        QNetworkRequest request(url);
    
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    
        connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(sakinAlCevap(QNetworkReply *)));
    
        manager->get(request);
    
    
    }
    
    void SakinlerListesi::sakinAlCevap(QNetworkReply *reply)
    {
        QString gelenCevap = reply->readAll().trimmed();
    
        //QMessageBox::information(this, "Dış IP Adresi", "Dış IP Adresiniz:\n" + gelenCevap);
    
        QString takas = gelenCevap;
    
        QStringList list1 = takas.split("#");
    
        foreach(QString sakin, list1){
            donenSakinler.append(sakin);
        }
    
        //qDebug()<<donenSakinler;
    
        sayac = 1;
    
    
    
        //delete reply->manager(); //Kaynağı siler...
    
        //reply->manager() = nullptr; //Kaynağı siler...
    
    }
    
    
    
    
    int SakinlerListesi::rowCount(const QModelIndex &parent) const
    {
        // For list models only the root node (an invalid parent) should return the list's size. For all
        // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
        if (parent.isValid())
            return 0;
    
        // FIXME: Implement me!
    
        qDebug()<<donenSakinler.size();
        return donenSakinler.size();
    }
    
    QVariant SakinlerListesi::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid())
            return QVariant();
    
        // FIXME: Implement me!
    
    
        return QVariant(QStringLiteral("Deneme %1").arg(index.row()));
    }
    
    QHash<int, QByteArray> SakinlerListesi::roleNames() const
    {
        QHash<int, QByteArray> names;
    
        names[0] = "aciklama";
    
        return names;
    
    }
    
    
    
    bool SakinlerListesi::checkInternet()
    {
        QNetworkAccessManager nam;
        QNetworkRequest req(QUrl("http://www.google.com"));
        QNetworkReply* replyCheckInternet = nam.get(req);
        QEventLoop loop;
        QObject::connect(replyCheckInternet, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec();
        if (replyCheckInternet->bytesAvailable())
        {
            delete replyCheckInternet;
            return true;
         }
        else
        {
            delete replyCheckInternet;
            return false;
        }
    }
    
    

    How va I fill the data in Item Model with the names returning from my web page?

    Regards,
    Mucip:)



  • @Mucip
    Your sakinAlCevap() is supposed to be filling donenSakinler. We can't tell what data it receives to know what it is putting there, you need to put in qDebug() statements.

    You look like you're calling sakinAl() very early. sakinAlCevap() will not be called until the reply is received, yet you expect donenSakinler to be populated immediately after calling sakinAl(), which will not be the case yet.

    Separately, your SakinlerListesi::data() should not return your QVariant(QStringLiteral("Deneme %1").arg(index.row())) unconditionally as you show, you must look at the role parameter (i.e. only do so for Qt::DisplayRole/EditRole.

    Separately, your QNetworkAccessManager * manager = new QNetworkAccessManager(this); is leaked.



  • Hi @JonB ,
    Qdebug output is:

    ()
    0
    ()
    0
    0
    0
    qrc:/Page4Form.ui.qml:21:5: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function.
    ("1-Lütfü ULUMAN", "2-Duygu TESGİ", "3-Tevhide Hanım", "4-Kübra ÇELİK", "5-Kadir YALTIR", "6-Ahmet KOCAHAN", "7-Murat DENİZ", "8-Birdal ÖZCAN", "9-Ömer ORAK", "10-Berkin ALTUNSOY", "11-Volkan TONCA", "12-Ömer AKSOY", "13-Mucibirahman İLBUĞA", "14-Kerem KEPENCİ", "15-Hasan Masat", "16-Modüler Sigorta", "17-Eczane Uğurlu", "18-Gökhan KUŞÇU")
    ("1-Lütfü ULUMAN", "2-Duygu TESGİ", "3-Tevhide Hanım", "4-Kübra ÇELİK", "5-Kadir YALTIR", "6-Ahmet KOCAHAN", "7-Murat DENİZ", "8-Birdal ÖZCAN", "9-Ömer ORAK", "10-Berkin ALTUNSOY", "11-Volkan TONCA", "12-Ömer AKSOY", "13-Mucibirahman İLBUĞA", "14-Kerem KEPENCİ", "15-Hasan Masat", "16-Modüler Sigorta", "17-Eczane Uğurlu", "18-Gökhan KUŞÇU")
    17:04:52: D:\Belgeler\Qt\build-MobilApt-Desktop_Qt_5_14_2_MSVC2017_64bit-Release\release\MobilApt.exe exited with code 0
    
    

    As you see in the begining the " donenSakinler.count(); " retuen 0. I could not undrstand this?
    But in the end I cann see the number and names filled in the donenSakinler statement.?!

    I could not understand when the system call data function. I need to fill donenSakinler statement first then call "data" function. But I don't know how to do this.

    By the way "QVariant(QStringLiteral("Deneme %1").arg(index.row()))" is only test. I want to fill like

    QVariant(QStringLiteral(donenSakinler[1]);
    QVariant(QStringLiteral(donenSakinler[2]);
    QVariant(QStringLiteral(donenSakinler[3]);
    QVariant(QStringLiteral(donenSakinler[4]);
    .
    .
    .
    .
    etc.
    

    I could fill the donenSakinler QList but I can not load this list in to QtItemModel unfortunately yet. :(

    Regards,
    Mucip:)



  • @JonB ,
    By the way, I could not understand?
    When th object call

    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    
    

    these two functions. How can I call them again after than internet request finished?

    Regards,
    Mucip:)



  • @Mucip said in How to fill data Qt Item Model:

    I need to fill donenSakinler statement first then call "data" function. But I don't know how to do this.

    This way is not the best. You don't have to "force" rowCount() to be right from the start. Leave your request to fill the array in the background.

    You really need to read and understand what you're supposed to do when subclassing QAbstractListModel, https://doc.qt.io/qt-5/qabstractlistmodel.html#subclassing. When you put new data into the model (e.g. your donenSakinler.append(sakin), called when parsing the reply) you should be calling begin/endInsertRows() as it explains there. Then any view attached to the model will see the additions.

    The above is the right way to go about things, but requires some understanding. Otherwise, you must find a way to block during SakinlerListesi::SakinlerListesi() till the reply is received synchronously, so that your data/rowCount() is valid before you try to read them. Which is not so nice.



  • @Mucip said in How to fill data Qt Item Model:

    How can I call them again after than internet request finished?

    Read my post above which has just crossed with yours.

    Basically you do not "call them again after than internet request finished?". You simply cannot afford to call them (to get the expected answer) until the request is finished. It's your task not to do so beforehand, else they will not be right. They just reflect whatever is in the data at the instant you do call them.

    If you do the beginInsertRows() I mentioned then the Qt infrastructure will see your new rows and change their return values correspondingly.

    If you really want to be lazy and "block" until the request finishes, you can always put in a suitable QEventLoop::exec(), which you terminate from the request finished() signal, just like you do for your replyCheckInternet presently.


Log in to reply