Results 1 to 9 of 9

Thread: qt5 QAbstractListModel C++ model in QML

  1. #1
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default qt5 QAbstractListModel C++ model in QML

    Here is my code for a listView model. It compiles part way and then hangs. I'm not sure if I need to declare msg QList as pointer or not (sidebar: if I do would like to allocate memory on the heap, to do I use the keyword "new"?). It seems to hang on setting the context property in main.cpp when I run the debugger with break points. This all new to me so I'm still sorting out how everything works together in the model to put data in a list to display. My understanding is I create a model in C++ which must include the rowCount(), roleNames(), data() functions. Will also need an enum var to declare the roleNames to be used. Will also need some sort of data structure (struct) to store the data from the database using roleNames. I believe the roleNames have to be the same name as the column header in the sqlite database. I use a sql statement to select data from the database then I loop through the query and add it to the data struct. Use the data struct to populate the list. each row I pull from the database is an element of the list. Is this understanding correct? I think one thing I have trouble with is managing the pointer I'm using... Also little fuzzy on setting the root context (methodology) I know this is a lot but I'm learning and any help is appreciated.

    background:
    I need to create a user event log that monitors the activity of a user in an application (weld programming application).

    I have created a new class to push user events to a database e.g. when they change settings or change weld program. (I have completed this part successfully).


    now I need to display this information in a dialogue for viewing so that managers can monitor employee activity in the application.


    Evidently I need to be able to filter by date and by user once I can get the display working. Also need to figure out how to create a new table every day and delete old tables after 30 days I figure I can create method to create tables and delete tables. Then is just pretty-up the display.
    I have decided to use C++ model to display this and the application GUI is in QML so will need to display in QML I'm using Qt5.5


    Qt Code:
    1. #ifndef SQLITEMODEL_H
    2. #define SQLITEMODEL_H
    3.  
    4. #include <assert.h>
    5. #include <list>
    6. #include <QList>
    7. #include <QColor>
    8. #include <QObject>
    9. #include <QDebug>
    10. #include <QString>
    11. #include <QFileInfo>
    12. #include <QDateTime>
    13. #include <QQmlError>
    14. #include <QQmlApplicationEngine>
    15. #include <QQmlEngine>
    16. #include <QQmlContext>
    17. #include <QtSql/QSqlDatabase>
    18. #include <QtSql/QSqlQuery>
    19. #include <QtSql/QSqlError>
    20. #include <QtSql/QSqlRecord>
    21. #include <QModelIndex>
    22. #include <QAbstractListModel>
    23.  
    24. struct userEventLogMsg{
    25. //hold all values for a single list entry,
    26. QString id;
    27. QString username;
    28. QString eventmessage;
    29. QDateTime datetime;
    30. };
    31.  
    32. class sqliteModel:public QAbstractListModel
    33. {
    34. Q_OBJECT
    35.  
    36. public:
    37. explicit sqliteModel(QObject *parent = 0);
    38.  
    39. ~sqliteModel();
    40.  
    41. enum userEventRoles {idRole, nameRole, msgRole, dateRole = Qt::UserRole + 220};
    42.  
    43. int rowCount(const QModelIndex & parent) const;
    44.  
    45. QHash<int, QByteArray> roleNames() const;
    46.  
    47. QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
    48.  
    49. void addEvent(const userEventLogMsg &msg);
    50.  
    51. private:
    52. QList<userEventLogMsg> m_msgList;
    53. };
    54.  
    55. #endif // SQLITEMODEL_H
    To copy to clipboard, switch view to plain text mode 

    =========================================== CPP FILE =================================================

    Qt Code:
    1. #include "sqlitemodel.h"
    2.  
    3. sqliteModel::sqliteModel(QObject *parent):QAbstractListModel(parent)
    4. {
    5.  
    6. }
    7.  
    8. sqliteModel::~sqliteModel()
    9. {
    10.  
    11. }
    12.  
    13. int sqliteModel::rowCount(const QModelIndex &parent) const
    14. {
    15. Q_UNUSED(parent);
    16. return m_msgList.count();
    17. qDebug()<< m_msgList.count();
    18. }
    19.  
    20. QHash<int, QByteArray> sqliteModel::roleNames() const
    21. {
    22. QHash<int, QByteArray> roleNames;
    23. roleNames.insert(idRole, "id");
    24. roleNames.insert(nameRole, "userName");
    25. roleNames.insert(msgRole, "eventMessage");
    26. roleNames.insert(dateRole, "dateTime");
    27. qDebug()<< roleNames;
    28. return roleNames;
    29. }
    30.  
    31. QVariant sqliteModel::data(const QModelIndex &index, int role) const
    32. {
    33. if (index.row() < 0 || index.row() >= m_msgList.count())
    34. {
    35. return QVariant();
    36. qDebug() << index.row();
    37. }
    38.  
    39. QVariant text;
    40.  
    41. if(role == idRole)
    42. {
    43. userEventLogMsg msg = m_msgList.at(0);
    44. text = msg.id;
    45. qDebug() << text;
    46. }
    47. else if(role == nameRole)
    48. {
    49. userEventLogMsg msg = m_msgList.at(1);;
    50. text = msg.username;
    51. qDebug() << text;
    52. }
    53. else if(role == msgRole)
    54. {
    55. userEventLogMsg msg = m_msgList.at(2);;
    56. text = msg.eventmessage;
    57. qDebug() << text;
    58. }
    59. if(role == dateRole)
    60. {
    61. userEventLogMsg msg = m_msgList.at(3);
    62. text = msg.datetime.toLocalTime().toString("M'/'d'/'yyyy' 'h:mm:ss ap" );
    63. qDebug() << text;
    64. }
    65. qDebug() << text;
    66. return text;
    67. }
    68.  
    69. void sqliteModel::addEvent(const userEventLogMsg &msg)
    70. {
    71. qDebug()<<"made it inside addEvent 1";
    72. beginInsertRows(QModelIndex(), 0, 0);
    73. qDebug()<<"made it inside addEvent 2";
    74. //m_msgList->insert(0, msg);
    75. m_msgList.append(msg);
    76. //qDebug() << m_msgList;
    77.  
    78. endInsertRows();
    79. }
    To copy to clipboard, switch view to plain text mode 
    ============================================ main.cpp ================================================

    Qt Code:
    1. #include <QGuiApplication>
    2. #include <QQmlApplicationEngine>
    3. #include <QSqlDatabase>
    4. #include "sqlitemodel.h"
    5.  
    6. int main(int argc, char *argv[])
    7. {
    8. QGuiApplication app(argc, argv);
    9.  
    10. sqliteModel *model = new sqliteModel;
    11.  
    12. db = QSqlDatabase::addDatabase("QSQLITE");
    13. db.setDatabaseName("/home/amet/git/rnd/userLog.db");
    14. db.open();
    15.  
    16. if(!db.open()){
    17. qDebug() <<"error in opening DB";
    18. }
    19. else{
    20. qDebug() <<"connected to DB" ;
    21. }
    22.  
    23. QSqlQuery myQuery("SELECT id, userName, eventMessage, dateTime FROM userlogevents");
    24.  
    25. if(myQuery.exec("SELECT id, userName, eventMessage, dateTime FROM userlogevents")){
    26. qDebug()<<"sql statement exicuted fine";
    27. }
    28. else{
    29. qDebug() <<"Errors accured with sql statement";
    30. qDebug() <<myQuery.lastError();
    31. }
    32.  
    33. while (myQuery.next()){
    34. userEventLogMsg *msg = new userEventLogMsg;
    35. QString myString = myQuery.value(0).toString();
    36. msg->id.insert(0, myString);
    37. //msg->username.append(myQuery.value(3).toString());
    38. //msg->eventmessage.append(myQuery.value(4).toString());
    39. //msg->datetime.append(myQuery.toLocalTime().toString("M'/'d'/'yyyy' 'h:mm:ss ap'"));
    40. model->addEvent(*msg);
    41. }
    42.  
    43. QQmlApplicationEngine engine;
    44. QQmlContext *contxt = engine.rootContext();
    45. contxt->setContextProperty("sqliteModel", model);
    46. return app.exec();
    47. }
    To copy to clipboard, switch view to plain text mode 

    ============================================ main QML ================================================

    Qt Code:
    1. import QtQuick 2.6
    2. import QtQuick.Layouts 1.1
    3. import QtQuick.Controls 1.3
    4. import QtQuick.Window 2.2
    5. import QtQuick.Dialogs 1.2
    6. import QtQuick.Layouts 1.1
    7. import QtQuick.Controls 2.0
    8. import Qt.labs.folderlistmodel 2.1
    9.  
    10. //---/ Display Rows from database in tableView /---//
    11. Window
    12. {
    13. ListView
    14. {
    15. width: 600; height: 250
    16. //---/ C++ model set using context property in main.cpp /---//
    17. model: sqliteModel
    18. //---// items are drawn by a delegate. /---//
    19. delegate: Text { text: "Record: " + id + ", " + ", " + userName + ", " + eventMessage + ", " + dateTime}
    20. }
    21. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: qt5 QAbstractListModel C++ model in QML

    Quote Originally Posted by jfinn88 View Post
    if I do would like to allocate memory on the heap, to do I use the keyword "new"?).
    Yes.
    But QList will allocate its memory on the heap anyway.

    Quote Originally Posted by jfinn88 View Post
    It seems to hang on setting the context property in main.cpp when I run the debugger with break points.
    strange, that part looks ok.
    You are just not loading any QML.

    Quote Originally Posted by jfinn88 View Post
    My understanding is I create a model in C++ which must include the rowCount(), roleNames(), data() functions.
    Yes, correct.
    rowCount() and data() are pure virtual and need to be implemented in order to the class to be instantiable.
    roleNames() is necessary for the QML integration.

    Quote Originally Posted by jfinn88 View Post
    Will also need an enum var to declare the roleNames to be used.
    You already have the enum for the roles.
    The only thing there is that you need to base the first enum relative to Qt::UserRole, otherwise the first role's integer value will be 0.

    Quote Originally Posted by jfinn88 View Post
    I believe the roleNames have to be the same name as the column header in the sqlite database.
    No, these do not have to relate.
    The role names are purely for the QML engine.

    Quote Originally Posted by jfinn88 View Post
    I use a sql statement to select data from the database then I loop through the query and add it to the data struct.
    You don't need to allocate the instance with new, in fact you are currently leaking each object.

    Quote Originally Posted by jfinn88 View Post
    Use the data struct to populate the list.
    There is currently a mismatch between what you tell beginInsertRows() and usng append().
    Your beginInsertRows() values say that you are adding the new entry at the beginning, while append() then actually adds it to the end of the list.

    Quote Originally Posted by jfinn88 View Post
    each row I pull from the database is an element of the list. Is this understanding correct?
    Yes.

    Your data() method is currently incorrect though.
    The role selects which of the fields of one entry you need to return, that part is correct.

    But which message to get from the list needs to be derived from the index, i.e. the message that is shown in the respective row.

    Alternatively to creatng your own list model you could consider deriving from QSqlQueryModel, adding roleNames() and modifying data() such that is used the role information so that it ask the base class for the right column.

    Cheers,
    _

  3. #3
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: qt5 QAbstractListModel C++ model in QML

    Okay I fixed my enumuration var

    Qt Code:
    1. enum userEventRoles {idRole= Qt::UserRole + 220, nameRole, msgRole, dateRole};
    To copy to clipboard, switch view to plain text mode 

    I still don't fully understand the Roles concept....

    ================================================== ===========================================

    Quote Originally Posted by anda_skoa View Post
    You don't need to allocate the instance with new, in fact you are currently leaking each object.
    What do you mean leaking objects ? I'm I miss handling something...?

    ================================================== ===========================================

    Quote Originally Posted by anda_skoa View Post
    strange, that part looks ok.
    You are just not loading any QML.
    If setting the contextProperty is fine how do I get the QML to load?

    ================================================== ===========================================

    Quote Originally Posted by anda_skoa View Post
    Your data() method is currently incorrect though.
    The role selects which of the fields of one entry you need to return, that part is correct.
    But which message to get from the list needs to be derived from the index, i.e. the message that is shown in the respective row.
    Can you explain this part that I'm messing up on more?

    ================================================== ===========================================

    Quote Originally Posted by anda_skoa View Post
    There is currently a mismatch between what you tell beginInsertRows() and usng append().
    Your beginInsertRows() values say that you are adding the new entry at the beginning, while append() then actually adds it to the end of the list.
    Switch back to insert function but not sure if it works...

    Qt Code:
    1. void sqliteModel::addEvent(const userEventLogMsg &msg)
    2. {
    3. qDebug()<<"made it inside addEvent 1";
    4. beginInsertRows(QModelIndex(), 0, 0);
    5. qDebug()<<"made it inside addEvent 2";
    6. m_msgList->insert(0, msg);
    7. endInsertRows();
    8. }
    To copy to clipboard, switch view to plain text mode 

    ================================================== ===========================================

    Quote Originally Posted by anda_skoa View Post
    Alternatively to creatng your own list model you could consider deriving from QSqlQueryModel, adding roleNames() and modifying data() such that is used the role information so that it ask the base class for the right column.
    I would like to see if I can get the model to display in QML first however I have tried using QSqlQuerModel (most likely improperly) with no avail. Once I get the sqlite data to display in QML could you help me implement the QSqlQueryModel ? Could you possibly help me set that up properly once I can get the listView to display?

    ================================================== ===================
    update 1:
    change userEventLogMsg to normal object (no pointer)

    update 2:

    when I set break point at:

    Qt Code:
    1. QQmlContext *contxt = engine.rootContext();
    To copy to clipboard, switch view to plain text mode 

    The app hangs here and debugger shows: "QML Debugger: Waiting for connection on port 54009..." -> is this the issue why the qml wont load I cant even get a window to show it doesn't compile that far.
    Last edited by jfinn88; 19th August 2016 at 18:38.

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: qt5 QAbstractListModel C++ model in QML

    Quote Originally Posted by jfinn88 View Post
    I still don't fully understand the Roles concept....
    Roles initially were meant to have access to several aspects of a single model cell, e.g. the value itself, font to use, text alignment, etc.

    In the context of QML the role is more used to have multiple data elements per entry.

    Quote Originally Posted by jfinn88 View Post
    What do you mean leaking objects ? I'm I miss handling something...?
    Leaking means that memory is lost.
    You are allocating userEventLogMsg objects on the heap (using new) but not releasing that memory with delete anywhere.

    Quote Originally Posted by jfinn88 View Post
    If setting the contextProperty is fine how do I get the QML to load?
    QQmlApplicationEngine::load().


    Quote Originally Posted by jfinn88 View Post
    Can you explain this part that I'm messing up on more?
    You are using hardcoded numbers to access which message you are getting the data from instead of using the row information of the index argument.

    Quote Originally Posted by jfinn88 View Post
    Switch back to insert function but not sure if it works...
    yes, that is consistent now. changing the arguments to beginInsertRows() would have been the other option.

    Quote Originally Posted by jfinn88 View Post
    I would like to see if I can get the model to display in QML first however
    Sensible approach, I agree.

    Quote Originally Posted by jfinn88 View Post
    I have tried using QSqlQuerModel (most likely improperly) with no avail. Once I get the sqlite data to display in QML could you help me implement the QSqlQueryModel ? Could you possibly help me set that up properly once I can get the listView to display?
    if your custom model starts working you should just keep using it.
    The other approach is mainly interesting when the same model should also be shown in a QtWidget table view.


    Quote Originally Posted by jfinn88 View Post
    The app hangs here and debugger shows: "QML Debugger: Waiting for connection on port 54009..." -> is this the issue why the qml wont load I cant even get a window to show it doesn't compile that far.
    If your program runs then it has already fully compiled.
    And you program doesn't hang, it just doesn't do anything because it doesn't have anything to do since you haven't loaded any UI.

    You currently have a QML engine that has access to the model but nothing is using that model.

    Cheers,
    _

    Quote Originally Posted by jfinn88 View Post
    I still don't fully understand the Roles concept....
    Roles initially were meant to have access to several aspects of a single model cell, e.g. the value itself, font to use, text alignment, etc.

    In the context of QML the role is more used to have multiple data elements per entry.

    Quote Originally Posted by jfinn88 View Post
    What do you mean leaking objects ? I'm I miss handling something...?
    Leaking means that memory is lost.
    You are allocating userEventLogMsg objects on the heap (using new) but not releasing that memory with delete anywhere.

    Quote Originally Posted by jfinn88 View Post
    If setting the contextProperty is fine how do I get the QML to load?
    QQmlApplicationEngine::load().


    Quote Originally Posted by jfinn88 View Post
    Can you explain this part that I'm messing up on more?
    You are using hardcoded numbers to access which message you are getting the data from instead of using the row information of the index argument.

    Quote Originally Posted by jfinn88 View Post
    Switch back to insert function but not sure if it works...
    yes, that is consistent now. changing the arguments to beginInsertRows() would have been the other option.

    Quote Originally Posted by jfinn88 View Post
    I would like to see if I can get the model to display in QML first however
    Sensible approach, I agree.

    Quote Originally Posted by jfinn88 View Post
    I have tried using QSqlQuerModel (most likely improperly) with no avail. Once I get the sqlite data to display in QML could you help me implement the QSqlQueryModel ? Could you possibly help me set that up properly once I can get the listView to display?
    if your custom model starts working you should just keep using it.
    The other approach is mainly interesting when the same model should also be shown in a QtWidget table view.


    Quote Originally Posted by jfinn88 View Post
    The app hangs here and debugger shows: "QML Debugger: Waiting for connection on port 54009..." -> is this the issue why the qml wont load I cant even get a window to show it doesn't compile that far.
    If your program runs then it has already fully compiled.
    And you program doesn't hang, it just doesn't do anything because it doesn't have anything to do since you haven't loaded any UI.

    You currently have a QML engine that has access to the model but nothing is using that model.

    Cheers,
    _

  5. #5
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: qt5 QAbstractListModel C++ model in QML

    Okay I see why QML wasn’t loading I wasnt calling it to load lol
    used my engine object and pass it the qml file to load.

    Qt Code:
    1. QQmlApplicationEngine engine;
    2. QQmlContext *contxt = engine.rootContext();
    3. contxt->setContextProperty("sqliteModel", model);
    4. engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    5. return app.exec();
    To copy to clipboard, switch view to plain text mode 

    app complies further along

    debug statements:
    Qt Code:
    1. QML debugging is enabled. Only use this in a safe environment.
    2. connected to DB
    3. sql statement exicuted fine
    4. made it inside addEvent 1
    5. made it inside addEvent 2
    6. made it inside addEvent 1
    7. made it inside addEvent 2
    8. QHash((478, "eventMessage")(479, "dateTime")(476, "id")(477, "userName"))
    9. ASSERT failure in QList<T>::at: "index out of range", file /opt/qt55/include/QtCore/qlist.h, line 510
    To copy to clipboard, switch view to plain text mode 

    However I'm running into and issue with my QList (index out of range) is it not declaring memory space for the list? QList should create memory location on the Heap automatically right?

    update: thought it might be my insert() function call but after running through the debugger it looks like getting error from: Signal: SIGABRT
    Qt Code:
    1. userEventLogMsg msg = m_msgList.at(0);
    To copy to clipboard, switch view to plain text mode 


    Added after 5 minutes:


    "Leaking means that memory is lost.
    You are allocating userEventLogMsg objects on the heap (using new) but not releasing that memory with delete anywhere."

    I might be getting the two confused but doesn’t the heap de-allocate memory for you? or is that the memory on the stack?

    I removed the new declaration from my msg userEventLogMsg obj

    Qt Code:
    1. while (myQuery.next()){
    2. userEventLogMsg msg;
    3. QString myString = myQuery.value(0).toString();
    4. msg.id.insert(0, myString);
    5. model->addEvent(msg);
    6. }
    To copy to clipboard, switch view to plain text mode 

    "You are using hardcoded numbers to access which message you are getting the data from instead of using the row information of the index argument."

    How would I do this? little confused sorry (update: use the index row from message list)

    Updated code:
    Qt Code:
    1. QVariant sqliteModel::data(const QModelIndex &index, int role) const
    2. {
    3. if (index.row() < 0 || index.row() >= m_msgList.count())
    4. {
    5. return QVariant();
    6. }
    7.  
    8. QVariant text;
    9.  
    10. if(role == idRole)
    11. {
    12. userEventLogMsg msg = m_msgList[index.row()];
    13. text = msg.id;
    14. qDebug() << text;
    15. }
    16. else if(role == nameRole)
    17. {
    18. userEventLogMsg msg = m_msgList[index.row()];
    19. text = msg.username;
    20. qDebug() << text;
    21. }
    22. else if(role == msgRole)
    23. {
    24. userEventLogMsg msg = m_msgList[index.row()];
    25. text = msg.eventmessage;
    26. qDebug() << text;
    27. }
    28. if(role == dateRole)
    29. {
    30. userEventLogMsg msg = m_msgList[index.row()];
    31. text = msg.datetime.toLocalTime().toString("M'/'d'/'yyyy' 'h:mm:ss ap" );
    32. qDebug() << text;
    33. }
    34. return text;
    35. }
    36. }
    37.  
    38. //While loop form main.cpp
    39. while (myQuery.next()){
    40. userEventLogMsg msg;
    41.  
    42. QString idString = myQuery.value(0).toString();
    43. msg.id.insert(0, idString);
    44.  
    45. QString userString = myQuery.value(3).toString();
    46. msg.username.insert(1, userString);
    47.  
    48. QString eventString = myQuery.value(4).toString();
    49. msg.eventmessage.insert(2, eventString);
    50.  
    51. QString dateString = myQuery.value(5).toString();
    52. msg.datetime.insert(3, dateString);
    53.  
    54. model->addEvent(msg);
    55. }
    To copy to clipboard, switch view to plain text mode 

    update: Have an issue trying to insert() my datetime (error QDateTime has no member named insert) what other function call can i use to get datetime data into the struct var?

    update: changed datetime data Type from QDateTime to QString. (date is formatted in database no need for QdateTime?)

    update: Ran through debugger set break point at
    Qt Code:
    1. return exec()
    To copy to clipboard, switch view to plain text mode 
    in main.cpp, and break point at
    Qt Code:
    1. model: sqliteModel
    To copy to clipboard, switch view to plain text mode 
    segmentation fault (SIGSEGV) when model is called in QML?
    Qt Code:
    1. model: sqliteModel
    To copy to clipboard, switch view to plain text mode 
    my Model declaration is one of two pointers I use so far in this app
    Qt Code:
    1. sqliteModel *model = new sqliteModel;
    2. QmlContext *contxt = engine.rootContext();
    To copy to clipboard, switch view to plain text mode 
    How do I manage the model pointer not to cause a seg fault ? How do I properly call/pass the C++ model to QML ?
    Qt Code:
    1. //---/ Display Rows from database in tableView /---//
    2. Window
    3. {
    4. ListView
    5. {
    6. width: 600; height: 250
    7. //---/ C++ model set using context property in main.cpp /---//
    8. model: sqliteModel
    9. //---// items are drawn by a delegate. /---//
    10. delegate: Text { text: "Record: " + id + ", " + userName + ", " + eventMessage + ", " + dateTime}
    11. }
    12. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by jfinn88; 19th August 2016 at 23:56.

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: qt5 QAbstractListModel C++ model in QML

    Quote Originally Posted by jfinn88 View Post
    app complies further along
    It runs further along.
    It has already finished compiling before, otherwise it wouldn't be possible to run it at all.

    Quote Originally Posted by jfinn88 View Post
    However I'm running into and issue with my QList (index out of range) is it not declaring memory space for the list? QList should create memory location on the Heap automatically right?
    Yes, it does.
    For all elements added to it.
    If you are trying to access any index that is not valid, it will assert.

    Quote Originally Posted by jfinn88 View Post
    update: thought it might be my insert() function call but after running through the debugger it looks like getting error from: Signal: SIGABRT
    Qt Code:
    1. userEventLogMsg msg = m_msgList.at(0);
    To copy to clipboard, switch view to plain text mode 
    That would mean that you are trying to access the first item while the list is still empty.

    Quote Originally Posted by jfinn88 View Post
    I might be getting the two confused but doesn’t the heap de-allocate memory for you? or is that the memory on the stack?
    Objects on the stack are deleted automatically, raw pointers allocated with new need to be deleted somewhere.

    Quote Originally Posted by jfinn88 View Post
    I removed the new declaration from my msg userEventLogMsg obj
    Yes, that looks better.

    Quote Originally Posted by jfinn88 View Post
    Qt Code:
    1. //While loop form main.cpp
    2. while (myQuery.next()){
    3. userEventLogMsg msg;
    4.  
    5. QString idString = myQuery.value(0).toString();
    6. msg.id.insert(0, idString);
    7.  
    8. QString userString = myQuery.value(3).toString();
    9. msg.username.insert(1, userString);
    10.  
    11. QString eventString = myQuery.value(4).toString();
    12. msg.eventmessage.insert(2, eventString);
    13.  
    14. QString dateString = myQuery.value(5).toString();
    15. msg.datetime.insert(3, dateString);
    16.  
    17. model->addEvent(msg);
    18. }
    To copy to clipboard, switch view to plain text mode 
    Why do you call insert on the members of the struct?
    If they were not empty to begin with (as they are newly constructed), you would end up with values that have the previous content and the new content from the query prepended to that.
    But your intention here is to get the values from the query into the struct, not modify the values in the struct.

    Quote Originally Posted by jfinn88 View Post
    update: Have an issue trying to insert() my datetime (error QDateTime has no member named insert) what other function call can i use to get datetime data into the struct var?
    Not really a problem since you don't want to do insert anyway.
    Just assign.

    Quote Originally Posted by jfinn88 View Post
    update: changed datetime data Type from QDateTime to QString. (date is formatted in database no need for QdateTime?)
    That's of course up to you.

    Quote Originally Posted by jfinn88 View Post
    How do I manage the model pointer not to cause a seg fault ? How do I properly call/pass the C++ model to QML ?
    That part of the code looks correct.

    Cheers,
    _

  7. #7
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: qt5 QAbstractListModel C++ model in QML

    Quote Originally Posted by anda_skoa View Post
    It runs further along.
    It has already finished compiling before, otherwise it wouldn't be possible to run it at all.
    -Yes it runs further along that was horrible wording by my part. It compiles and is running I was just having issue displaying QML.

    Why do you call insert on the members of the struct?_
    I take the results of the query and store them in strings and insert them into the data struct ?

    If they were not empty to begin with (as they are newly constructed), you would end up with values that have the previous content and the new content from the query prepended to that.
    But your intention here is to get the values from the query into the struct, not modify the values in the struct.
    em I modifying the values some how I don't see? Would append be better than insert?

    I made some good improvements based on your suggestions Updated code:

    ====================== MAIN.cpp ====================================
    Qt Code:
    1. #include <QGuiApplication>
    2. #include <QQmlApplicationEngine>
    3. #include <QSqlDatabase>
    4. #include "sqlitemodel.h"
    5. #include <QUrl>
    6.  
    7. int main(int argc, char *argv[])
    8. {
    9. QGuiApplication app(argc, argv);
    10.  
    11. sqliteModel *model = new sqliteModel;
    12.  
    13. db = QSqlDatabase::addDatabase("QSQLITE");
    14. db.setDatabaseName("/home/amet/userLog.db");
    15. db.open();
    16.  
    17. if(!db.open()){
    18. qDebug() <<"error in opening DB";
    19. }
    20. else{
    21. qDebug() <<"connected to DB" ;
    22. }
    23.  
    24. QSqlQuery myQuery("SELECT id, userName, eventMessage, dateTime FROM userlogevents");
    25.  
    26. if(myQuery.exec("SELECT id, userName, eventMessage, dateTime FROM userlogevents")){
    27. qDebug()<<"sql statement exicuted fine";
    28. }
    29. else{
    30. qDebug() <<"Errors accured with sql statement";
    31. qDebug() <<myQuery.lastError();
    32. }
    33.  
    34. while (myQuery.next()){
    35. userEventLogMsg msg;
    36.  
    37. QString idString = myQuery.value(0).toString();
    38. msg.id.insert(0, idString);
    39.  
    40. QString userString = myQuery.value(1).toString();
    41. msg.username.insert(1, userString);
    42.  
    43. QString eventString = myQuery.value(2).toString();
    44. msg.eventmessage.insert(2, eventString);
    45.  
    46. QString dateString = myQuery.value(3).toString();
    47. msg.datetime.insert(3, dateString);
    48.  
    49. model->addEvent(msg);
    50. }
    51.  
    52. QQmlApplicationEngine engine;
    53. QQmlContext *contxt = engine.rootContext();
    54. contxt->setContextProperty("sqliteModel", model);
    55. engine.load(QUrl("qrc:/main.qml"));
    56. return app.exec();
    57. }
    To copy to clipboard, switch view to plain text mode 

    ====================== sqliteModel.cpp ====================================
    Qt Code:
    1. #include "sqlitemodel.h"
    2.  
    3. sqliteModel::sqliteModel(QObject *parent):QAbstractListModel(parent)
    4. {
    5.  
    6. }
    7.  
    8. sqliteModel::~sqliteModel()
    9. {
    10.  
    11. }
    12.  
    13. int sqliteModel::rowCount(const QModelIndex &parent) const
    14. {
    15. Q_UNUSED(parent);
    16. return m_msgList.count();
    17. qDebug()<< m_msgList.count();
    18. }
    19.  
    20. QHash<int, QByteArray> sqliteModel::roleNames() const
    21. {
    22. QHash<int, QByteArray> roleNames;
    23. roleNames.insert(idRole, "id");
    24. roleNames.insert(nameRole, "userName");
    25. roleNames.insert(msgRole, "eventMessage");
    26. roleNames.insert(dateRole, "dateTime");
    27. qDebug()<< roleNames;
    28. return roleNames;
    29. }
    30.  
    31. QVariant sqliteModel::data(const QModelIndex &index, int role) const
    32. {
    33. if (index.row() < 0 || index.row() >= m_msgList.count())
    34. {
    35. return QVariant();
    36. }
    37.  
    38. QVariant text;
    39.  
    40. if(role == idRole)
    41. {
    42. userEventLogMsg msg = m_msgList[index.row()];
    43. text = msg.id;
    44. qDebug() << text;
    45. }
    46. else if(role == nameRole)
    47. {
    48. userEventLogMsg msg = m_msgList[index.row()];
    49. text = msg.username;
    50. qDebug() << text;
    51. }
    52. else if(role == msgRole)
    53. {
    54. userEventLogMsg msg = m_msgList[index.row()];
    55. text = msg.eventmessage;
    56. qDebug() << text;
    57. }
    58. if(role == dateRole)
    59. {
    60. userEventLogMsg msg = m_msgList[index.row()];
    61. text = msg.datetime;
    62. qDebug() << text;
    63. }
    64. return text;
    65. }
    66.  
    67. void sqliteModel::addEvent(const userEventLogMsg &msg)
    68. {
    69. beginInsertRows(QModelIndex(), 0, 0);
    70. m_msgList.insert(0, msg);
    71. endInsertRows();
    72.  
    73. //QListIterator<userEventLogMsg> iter(m_msgList);
    74. //while(iter.hasNext())
    75. //{
    76. // The next() function returns the next item in the list and advances the iterator.
    77. //qDebug() << iter.next();
    78. //}
    79. }
    To copy to clipboard, switch view to plain text mode 

    ====================== sqliteModel.h ====================================
    Qt Code:
    1. #ifndef SQLITEMODEL_H
    2. #define SQLITEMODEL_H
    3.  
    4. #include <assert.h>
    5. #include <list>
    6. #include <QList>
    7. #include <QColor>
    8. #include <QObject>
    9. #include <QDebug>
    10. #include <QString>
    11. #include <QFileInfo>
    12. #include <QDateTime>
    13. #include <QQmlError>
    14. #include <QQmlApplicationEngine>
    15. #include <QQmlEngine>
    16. #include <QQmlContext>
    17. #include <QtSql/QSqlDatabase>
    18. #include <QtSql/QSqlQuery>
    19. #include <QtSql/QSqlError>
    20. #include <QtSql/QSqlRecord>
    21. #include <QModelIndex>
    22. #include <QAbstractListModel>
    23. #include <QListIterator>
    24.  
    25. struct userEventLogMsg{
    26. //hold all values for a single list entry,
    27. QString id;
    28. QString username;
    29. QString eventmessage;
    30. QString datetime;
    31. };
    32.  
    33. class sqliteModel:public QAbstractListModel
    34. {
    35. Q_OBJECT
    36.  
    37. public:
    38. explicit sqliteModel(QObject *parent = 0);
    39.  
    40. ~sqliteModel();
    41.  
    42. enum userEventRoles {idRole= Qt::UserRole + 220, nameRole, msgRole, dateRole};
    43.  
    44. int rowCount(const QModelIndex & parent) const;
    45.  
    46. QHash<int, QByteArray> roleNames() const;
    47.  
    48. QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
    49.  
    50. void addEvent(const userEventLogMsg &msg);
    51.  
    52. private:
    53. QList<userEventLogMsg> m_msgList;
    54. };
    55.  
    56. #endif // SQLITEMODEL_H
    To copy to clipboard, switch view to plain text mode 

    ====================== sqliteModel.h ====================================
    Qt Code:
    1. import QtQuick 2.5
    2. import QtQuick.Layouts 1.1
    3. import QtQuick.Controls 1.3
    4. import QtQuick.Window 2.2
    5. import QtQuick.Dialogs 1.2
    6. import QtQuick.Layouts 1.1
    7. import QtQuick.Controls 1.4
    8. //import Qt.labs.folderlistmodel 2.1
    9.  
    10. //---/ Display Rows from database in tableView /---//
    11. Window
    12. {
    13. visible: true
    14. width: 760
    15. height: 410
    16.  
    17. TableView
    18. {
    19. width: 750;
    20. height: 350;
    21. horizontalScrollBarPolicy: 0
    22. frameVisible: true
    23. //---/ C++ model set using context property in main.cpp /---//
    24. model: sqliteModel
    25. //---// items are drawn by a delegate. /---//
    26. //Delegate: Text { text: "Record: " + id + ", " + userName + ", " + eventMessage + ", " + dateTime}
    27. TableViewColumn {
    28. role: "id"
    29. title: "id"
    30. width: 100
    31. }
    32. TableViewColumn {
    33. role: "userName"
    34. title: "User Name"
    35. width: 200
    36. }
    37. TableViewColumn {
    38. role: "eventMessage"
    39. title: "Event Message"
    40. width: 200
    41. }
    42. TableViewColumn {
    43. role: "dateTime"
    44. title: "Date Time"
    45. width: 200
    46. }
    47. }
    48.  
    49. Button {
    50. id: button1
    51. x: 665
    52. y: 366
    53. text: qsTr("Search")
    54. }
    55.  
    56. TextField {
    57. id: textField1
    58. x: 534
    59. y: 368
    60. width: 125
    61. height: 25
    62. placeholderText: qsTr("mm//dd/yyyy")
    63. }
    64.  
    65. Label {
    66. id: label1
    67. x: 467
    68. y: 371
    69. width: 39
    70. height: 17
    71. text: qsTr("Date")
    72. }
    73.  
    74. TextField {
    75. id: textField2
    76. x: 287
    77. y: 368
    78. placeholderText: qsTr("User Name")
    79. }
    80.  
    81. Label {
    82. id: label2
    83. x: 181
    84. y: 371
    85. text: qsTr("User Name")
    86. }
    87.  
    88. Row {
    89. id: row1
    90. x: 0
    91. y: 356
    92. width: 750
    93. height: 47
    94. }
    95. }
    To copy to clipboard, switch view to plain text mode 

  8. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: qt5 QAbstractListModel C++ model in QML

    Quote Originally Posted by jfinn88 View Post
    I take the results of the query and store them in strings and insert them into the data struct ?
    You are calling insert() on an empty string and the operation you want to have is not changing the string but replacing it.
    It doesn't make a difference here because the left hand side value is empty.

    The operation you need here logically is a value assignment
    Qt Code:
    1. msg.id = idString;
    To copy to clipboard, switch view to plain text mode 
    or even just
    Qt Code:
    1. msg.id = myQuery.value(0).toString();
    To copy to clipboard, switch view to plain text mode 

    Quote Originally Posted by jfinn88 View Post
    em I modifying the values some how I don't see? Would append be better than insert?
    Again it makes no difference in this case since the left hand side value is empty, but consider if it were not
    Qt Code:
    1. QString msgId = "foo";
    2. QString idString = "bar";
    3.  
    4. // msgId.insert(0, idString) => msgId == "barfoo"
    5. // msgId.append(idString) => msgId == "foobar"
    To copy to clipboard, switch view to plain text mode 
    Not at all what you would want, right?

    Quote Originally Posted by jfinn88 View Post
    I made some good improvements based on your suggestions Updated code:
    Btw, a qDebug() after a return will never ever be reached.
    Once a function hits a return statements it is done.

    Cheers,
    _

  9. #9
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: qt5 QAbstractListModel C++ model in QML

    You are calling insert() on an empty string and the operation you want to have is not changing the string but replacing it.
    It doesn't make a difference here because the left hand side value is empty.

    The operation you need here logically is a value assignment
    Qt Code:
    1. msg.id = idString;
    To copy to clipboard, switch view to plain text mode 
    or even just
    Qt Code:
    1. msg.id = myQuery.value(0).toString();
    To copy to clipboard, switch view to plain text mode 


    Again it makes no difference in this case since the left hand side value is empty, but consider if it were not
    Qt Code:
    1. QString msgId = "foo";
    2. QString idString = "bar";
    3.  
    4. // msgId.insert(0, idString) => msgId == "barfoo"
    5. // msgId.append(idString) => msgId == "foobar"
    To copy to clipboard, switch view to plain text mode 
    Not at all what you would want, right?
    You are correct I didn't think about it that in-depth yet. Thank you for the example with foo & bar

    Btw, a qDebug() after a return will never ever be reached.
    Once a function hits a return statements it is done.
    Yes, I noticed that as well meant to change it just forgot about it. I wasn't to worried about it thanks for the heads up.

Similar Threads

  1. Replies: 8
    Last Post: 11th March 2016, 10:56
  2. Replies: 1
    Last Post: 29th August 2013, 06:41
  3. ListView model binding to QAbstractListModel
    By michalk in forum Qt Quick
    Replies: 1
    Last Post: 16th July 2011, 10:21
  4. QAbstractListModel
    By Archa4 in forum Newbie
    Replies: 9
    Last Post: 9th February 2011, 15:43
  5. QAbstractListModel searching.
    By ComaWhite in forum Qt Programming
    Replies: 1
    Last Post: 15th June 2009, 19:41

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.