PDA

View Full Version : qt5 QAbstractListModel C++ model in QML



jfinn88
19th August 2016, 17:08
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




#ifndef SQLITEMODEL_H
#define SQLITEMODEL_H

#include <assert.h>
#include <list>
#include <QList>
#include <QColor>
#include <QObject>
#include <QDebug>
#include <QString>
#include <QFileInfo>
#include <QDateTime>
#include <QQmlError>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlContext>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>
#include <QModelIndex>
#include <QAbstractListModel>

struct userEventLogMsg{
//hold all values for a single list entry,
QString id;
QString username;
QString eventmessage;
QDateTime datetime;
};

class sqliteModel:public QAbstractListModel
{
Q_OBJECT

public:
explicit sqliteModel(QObject *parent = 0);

~sqliteModel();

enum userEventRoles {idRole, nameRole, msgRole, dateRole = Qt::UserRole + 220};

int rowCount(const QModelIndex & parent) const;

QHash<int, QByteArray> roleNames() const;

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

void addEvent(const userEventLogMsg &msg);

private:
QList<userEventLogMsg> m_msgList;
};

#endif // SQLITEMODEL_H


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



#include "sqlitemodel.h"

sqliteModel::sqliteModel(QObject *parent):QAbstractListModel(parent)
{

}

sqliteModel::~sqliteModel()
{

}

int sqliteModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_msgList.count();
qDebug()<< m_msgList.count();
}

QHash<int, QByteArray> sqliteModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames.insert(idRole, "id");
roleNames.insert(nameRole, "userName");
roleNames.insert(msgRole, "eventMessage");
roleNames.insert(dateRole, "dateTime");
qDebug()<< roleNames;
return roleNames;
}

QVariant sqliteModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_msgList.count())
{
return QVariant();
qDebug() << index.row();
}

QVariant text;

if(role == idRole)
{
userEventLogMsg msg = m_msgList.at(0);
text = msg.id;
qDebug() << text;
}
else if(role == nameRole)
{
userEventLogMsg msg = m_msgList.at(1);;
text = msg.username;
qDebug() << text;
}
else if(role == msgRole)
{
userEventLogMsg msg = m_msgList.at(2);;
text = msg.eventmessage;
qDebug() << text;
}
if(role == dateRole)
{
userEventLogMsg msg = m_msgList.at(3);
text = msg.datetime.toLocalTime().toString("M'/'d'/'yyyy' 'h:mm:ss ap" );
qDebug() << text;
}
qDebug() << text;
return text;
}

void sqliteModel::addEvent(const userEventLogMsg &msg)
{
qDebug()<<"made it inside addEvent 1";
beginInsertRows(QModelIndex(), 0, 0);
qDebug()<<"made it inside addEvent 2";
//m_msgList->insert(0, msg);
m_msgList.append(msg);
//qDebug() << m_msgList;

endInsertRows();
}

============================================ main.cpp ================================================



#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSqlDatabase>
#include "sqlitemodel.h"

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

sqliteModel *model = new sqliteModel;

QSqlDatabase db;
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("/home/amet/git/rnd/userLog.db");
db.open();

if(!db.open()){
qDebug() <<"error in opening DB";
}
else{
qDebug() <<"connected to DB" ;
}

QSqlQuery myQuery("SELECT id, userName, eventMessage, dateTime FROM userlogevents");

if(myQuery.exec("SELECT id, userName, eventMessage, dateTime FROM userlogevents")){
qDebug()<<"sql statement exicuted fine";
}
else{
qDebug() <<"Errors accured with sql statement";
qDebug() <<myQuery.lastError();
}

while (myQuery.next()){
userEventLogMsg *msg = new userEventLogMsg;
QString myString = myQuery.value(0).toString();
msg->id.insert(0, myString);
//msg->username.append(myQuery.value(3).toString());
//msg->eventmessage.append(myQuery.value(4).toString());
//msg->datetime.append(myQuery.toLocalTime().toString("M'/'d'/'yyyy' 'h:mm:ss ap'"));
model->addEvent(*msg);
}

QQmlApplicationEngine engine;
QQmlContext *contxt = engine.rootContext();
contxt->setContextProperty("sqliteModel", model);
return app.exec();
}


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



import QtQuick 2.6
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0
import Qt.labs.folderlistmodel 2.1

//---/ Display Rows from database in tableView /---//
Window
{
ListView
{
width: 600; height: 250
//---/ C++ model set using context property in main.cpp /---//
model: sqliteModel
//---// items are drawn by a delegate. /---//
delegate: Text { text: "Record: " + id + ", " + ", " + userName + ", " + eventMessage + ", " + dateTime}
}
}

anda_skoa
19th August 2016, 17:47
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.



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.



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.



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.



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.



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.



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.



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,
_

jfinn88
19th August 2016, 18:19
Okay I fixed my enumuration var


enum userEventRoles {idRole= Qt::UserRole + 220, nameRole, msgRole, dateRole};

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

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



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...?

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



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?

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



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?

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



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...



void sqliteModel::addEvent(const userEventLogMsg &msg)
{
qDebug()<<"made it inside addEvent 1";
beginInsertRows(QModelIndex(), 0, 0);
qDebug()<<"made it inside addEvent 2";
m_msgList->insert(0, msg);
endInsertRows();
}


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



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:


QQmlContext *contxt = engine.rootContext();

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.

anda_skoa
19th August 2016, 18:44
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.



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.



If setting the contextProperty is fine how do I get the QML to load?

QQmlApplicationEngine::load().




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.



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.



I would like to see if I can get the model to display in QML first however

Sensible approach, I agree.



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.




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,
_



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.



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.



If setting the contextProperty is fine how do I get the QML to load?

QQmlApplicationEngine::load().




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.



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.



I would like to see if I can get the model to display in QML first however

Sensible approach, I agree.



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.




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,
_

jfinn88
19th August 2016, 19:47
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.



QQmlApplicationEngine engine;
QQmlContext *contxt = engine.rootContext();
contxt->setContextProperty("sqliteModel", model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();


app complies further along

debug statements:


QML debugging is enabled. Only use this in a safe environment.
connected to DB
sql statement exicuted fine
made it inside addEvent 1
made it inside addEvent 2
made it inside addEvent 1
made it inside addEvent 2
QHash((478, "eventMessage")(479, "dateTime")(476, "id")(477, "userName"))
QVariant(QString, "2")
QVariant(QString, "2")
QVariant(QString, "")
QVariant(QString, "")
ASSERT failure in QList<T>::at: "index out of range", file /opt/qt55/include/QtCore/qlist.h, line 510


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
userEventLogMsg msg = m_msgList.at(0);

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



while (myQuery.next()){
userEventLogMsg msg;
QString myString = myQuery.value(0).toString();
msg.id.insert(0, myString);
model->addEvent(msg);
}


"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:


QVariant sqliteModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_msgList.count())
{
return QVariant();
}

QVariant text;

if(role == idRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.id;
qDebug() << text;
}
else if(role == nameRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.username;
qDebug() << text;
}
else if(role == msgRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.eventmessage;
qDebug() << text;
}
if(role == dateRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.datetime.toLocalTime().toString("M'/'d'/'yyyy' 'h:mm:ss ap" );
qDebug() << text;
}
return text;
}
}

//While loop form main.cpp
while (myQuery.next()){
userEventLogMsg msg;

QString idString = myQuery.value(0).toString();
msg.id.insert(0, idString);

QString userString = myQuery.value(3).toString();
msg.username.insert(1, userString);

QString eventString = myQuery.value(4).toString();
msg.eventmessage.insert(2, eventString);

QString dateString = myQuery.value(5).toString();
msg.datetime.insert(3, dateString);

model->addEvent(msg);
}


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
return exec() in main.cpp, and break point at
model: sqliteModel segmentation fault (SIGSEGV) when model is called in QML?
model: sqliteModel my Model declaration is one of two pointers I use so far in this app


sqliteModel *model = new sqliteModel;
QmlContext *contxt = engine.rootContext();
How do I manage the model pointer not to cause a seg fault ? How do I properly call/pass the C++ model to QML ?


//---/ Display Rows from database in tableView /---//
Window
{
ListView
{
width: 600; height: 250
//---/ C++ model set using context property in main.cpp /---//
model: sqliteModel
//---// items are drawn by a delegate. /---//
delegate: Text { text: "Record: " + id + ", " + userName + ", " + eventMessage + ", " + dateTime}
}
}

anda_skoa
20th August 2016, 12:25
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.



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.



update: thought it might be my insert() function call but after running through the debugger it looks like getting error from: Signal: SIGABRT
userEventLogMsg msg = m_msgList.at(0);

That would mean that you are trying to access the first item while the list is still empty.



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.



I removed the new declaration from my msg userEventLogMsg obj

Yes, that looks better.





//While loop form main.cpp
while (myQuery.next()){
userEventLogMsg msg;

QString idString = myQuery.value(0).toString();
msg.id.insert(0, idString);

QString userString = myQuery.value(3).toString();
msg.username.insert(1, userString);

QString eventString = myQuery.value(4).toString();
msg.eventmessage.insert(2, eventString);

QString dateString = myQuery.value(5).toString();
msg.datetime.insert(3, dateString);

model->addEvent(msg);
}


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.



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.



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.


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,
_

jfinn88
22nd August 2016, 17:41
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 ====================================


#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSqlDatabase>
#include "sqlitemodel.h"
#include <QUrl>

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

sqliteModel *model = new sqliteModel;

QSqlDatabase db;
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("/home/amet/userLog.db");
db.open();

if(!db.open()){
qDebug() <<"error in opening DB";
}
else{
qDebug() <<"connected to DB" ;
}

QSqlQuery myQuery("SELECT id, userName, eventMessage, dateTime FROM userlogevents");

if(myQuery.exec("SELECT id, userName, eventMessage, dateTime FROM userlogevents")){
qDebug()<<"sql statement exicuted fine";
}
else{
qDebug() <<"Errors accured with sql statement";
qDebug() <<myQuery.lastError();
}

while (myQuery.next()){
userEventLogMsg msg;

QString idString = myQuery.value(0).toString();
msg.id.insert(0, idString);

QString userString = myQuery.value(1).toString();
msg.username.insert(1, userString);

QString eventString = myQuery.value(2).toString();
msg.eventmessage.insert(2, eventString);

QString dateString = myQuery.value(3).toString();
msg.datetime.insert(3, dateString);

model->addEvent(msg);
}

QQmlApplicationEngine engine;
QQmlContext *contxt = engine.rootContext();
contxt->setContextProperty("sqliteModel", model);
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}


====================== sqliteModel.cpp ====================================


#include "sqlitemodel.h"

sqliteModel::sqliteModel(QObject *parent):QAbstractListModel(parent)
{

}

sqliteModel::~sqliteModel()
{

}

int sqliteModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_msgList.count();
qDebug()<< m_msgList.count();
}

QHash<int, QByteArray> sqliteModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames.insert(idRole, "id");
roleNames.insert(nameRole, "userName");
roleNames.insert(msgRole, "eventMessage");
roleNames.insert(dateRole, "dateTime");
qDebug()<< roleNames;
return roleNames;
}

QVariant sqliteModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_msgList.count())
{
return QVariant();
}

QVariant text;

if(role == idRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.id;
qDebug() << text;
}
else if(role == nameRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.username;
qDebug() << text;
}
else if(role == msgRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.eventmessage;
qDebug() << text;
}
if(role == dateRole)
{
userEventLogMsg msg = m_msgList[index.row()];
text = msg.datetime;
qDebug() << text;
}
return text;
}

void sqliteModel::addEvent(const userEventLogMsg &msg)
{
beginInsertRows(QModelIndex(), 0, 0);
m_msgList.insert(0, msg);
endInsertRows();

//QListIterator<userEventLogMsg> iter(m_msgList);
//while(iter.hasNext())
//{
// The next() function returns the next item in the list and advances the iterator.
//qDebug() << iter.next();
//}
}


====================== sqliteModel.h ====================================


#ifndef SQLITEMODEL_H
#define SQLITEMODEL_H

#include <assert.h>
#include <list>
#include <QList>
#include <QColor>
#include <QObject>
#include <QDebug>
#include <QString>
#include <QFileInfo>
#include <QDateTime>
#include <QQmlError>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlContext>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>
#include <QModelIndex>
#include <QAbstractListModel>
#include <QListIterator>

struct userEventLogMsg{
//hold all values for a single list entry,
QString id;
QString username;
QString eventmessage;
QString datetime;
};

class sqliteModel:public QAbstractListModel
{
Q_OBJECT

public:
explicit sqliteModel(QObject *parent = 0);

~sqliteModel();

enum userEventRoles {idRole= Qt::UserRole + 220, nameRole, msgRole, dateRole};

int rowCount(const QModelIndex & parent) const;

QHash<int, QByteArray> roleNames() const;

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

void addEvent(const userEventLogMsg &msg);

private:
QList<userEventLogMsg> m_msgList;
};

#endif // SQLITEMODEL_H


====================== sqliteModel.h ====================================


import QtQuick 2.5
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
//import Qt.labs.folderlistmodel 2.1

//---/ Display Rows from database in tableView /---//
Window
{
visible: true
width: 760
height: 410

TableView
{
width: 750;
height: 350;
horizontalScrollBarPolicy: 0
frameVisible: true
//---/ C++ model set using context property in main.cpp /---//
model: sqliteModel
//---// items are drawn by a delegate. /---//
//Delegate: Text { text: "Record: " + id + ", " + userName + ", " + eventMessage + ", " + dateTime}
TableViewColumn {
role: "id"
title: "id"
width: 100
}
TableViewColumn {
role: "userName"
title: "User Name"
width: 200
}
TableViewColumn {
role: "eventMessage"
title: "Event Message"
width: 200
}
TableViewColumn {
role: "dateTime"
title: "Date Time"
width: 200
}
}

Button {
id: button1
x: 665
y: 366
text: qsTr("Search")
}

TextField {
id: textField1
x: 534
y: 368
width: 125
height: 25
placeholderText: qsTr("mm//dd/yyyy")
}

Label {
id: label1
x: 467
y: 371
width: 39
height: 17
text: qsTr("Date")
}

TextField {
id: textField2
x: 287
y: 368
placeholderText: qsTr("User Name")
}

Label {
id: label2
x: 181
y: 371
text: qsTr("User Name")
}

Row {
id: row1
x: 0
y: 356
width: 750
height: 47
}
}

anda_skoa
22nd August 2016, 18:32
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


msg.id = idString;

or even just


msg.id = myQuery.value(0).toString();




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


QString msgId = "foo";
QString idString = "bar";

// msgId.insert(0, idString) => msgId == "barfoo"
// msgId.append(idString) => msgId == "foobar"

Not at all what you would want, right?



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,
_

jfinn88
23rd August 2016, 17:20
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


msg.id = idString;

or even just


msg.id = myQuery.value(0).toString();



Again it makes no difference in this case since the left hand side value is empty, but consider if it were not


QString msgId = "foo";
QString idString = "bar";

// msgId.insert(0, idString) => msgId == "barfoo"
// msgId.append(idString) => msgId == "foobar"

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.