PDA

View Full Version : Moving Script out of main.cpp to own .cpp file (MySQL)



shokarta
31st March 2019, 16:49
Hello guys,

im new in c++...
so I have come up with own function which I have placed into blank mysql.cpp (please note, the code bellow is ALL mysql.cpp content, there are no #includes or anything else:

void sql_insertValue(QString user, Qstring terminal, Qstring taskKind, Qstring taskType, Qstring timestamp)
{
QBool result;

// Sets database
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");,
db.setDatabaseName("terminals");
db.setUserName("root");
db.setPassword("");
if(!db.open()) { qDebug() << "MySQL ERROR: " << db.lastError().text(); }

QSqlQuery qry;
qry.prepare( "INSERT INTO records (user, kst, taskkind, taktype, timestamp) VALUES ('%1', '%2', '%3', '%4', '%5')" ).argv(user).argv(terminal).argv(taskKind).argv(ta skType).argv(timestamp);
if( !qry.exec() )
result = false;
else
result = true;

db.close();

return result;
}

so I dont know how to make this work when called from QML:
- meaning how to include this file from main.cpp
- how to register it as public function so i can call it from QML
- how to read result from QML: if(sql_insertValue(a,b,c,d)===true) { something }

If I can ask you to guide me as total noob, please do so as this is my (nearly) totaly first interact with c++ inside qt.

so I know main.cpp must mo modified, mysql.cpp must be modified (at least some includes), and also some import in qml should be done... probably something else...

Thank you

shokarta
1st April 2019, 19:59
I have got this far (with check connection first only):

mysql.h:

#ifndef MYSQL_H
#define MYSQL_H

#include <QObject>

class MySQL : public QObject
{
Q_OBJECT
public:
explicit MySQL(QObject *parent = 0);
Q_INVOKABLE void checkConnection();

signals:

public slots:

};

#endif // MYSQL_H

mysql.cpp:

#include "mysql.h"
#include <QtSql>
#include <QObject>

MySQL::MySQL(QObject *parent) :
QObject(parent)
{
}

void MySQL::checkConnection()
{
QString result;
// Sets database
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("terminals");
db.setUserName("root");
db.setPassword("");

if(db.open()) { qDebug() << "MySQL: Connected"; db.close(); result = "true"; }
else { qDebug() << "MySQL ERROR: " << db.lastError().text(); result = "false"; }

}

main.qml:

import QtQuick 2.12
import QtQuick.Controls 2.0
import QtQuick.LocalStorage 2.0
import MySQL 1.0
import 'JavaScript.js' as JS

Item {

MySQL {
id: sql
}

MouseArea {
anchors.fill: parent
onClicked: { sql.checkConnection(); }
}
}

main.cpp:

#include <QtCore>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtSql>
#include <QtDebug>
#include "mysql.h"

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

qmlRegisterType<MySQL>("MySQL", 1, 0, "MySQL");

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

// Sets path for SQLite
engine.setOfflineStoragePath("C:\\Terminal");

return app.exec();


this works like a charm!

i would like to ad the return ability, so from QML i can do something like:
if(sql.checkConnection()===true) { something } else { somethingelse }
- so it will return result variable from mysql.cpp

how to do this?

anda_skoa
2nd April 2019, 09:17
You simply change the return type of your function from "void" to the type you want to return, e.g. "bool" for a true/false value.

Then you can use one or more "return" lines inside the function.

Cheers,
_

shokarta
2nd April 2019, 16:27
wooow that was real simple :D

this brings additional 3 questions:
1) how do I move rows 13 to 18 in mysql.cpp above the void (now its bool), because I wish to have some more functions but the data for login to DB stays the same...
I have tried to move them just above the void (bool) function, but error uncnown type name 'db' and if i moved it inside MySQL::MySQL(QObject *parent): then I am getting error use of undeclared identifier 'db'

2) as soon as i request this function via MouseArea onclick, the whole application freezes for 3 sec till it return false as db unreachable (in case db is reachable, its just few milsec so its unnoticable). Is there anything what I can do? run the script on background or something?

3) can I somehow make a signal if connection status changes? so far I have timer that every 30 sec it will update and check if connection is available, but In case the status will changhe, is it possible that it will notify me myself like OnVariableChanges or something?

Thank you

anda_skoa
3rd April 2019, 07:55
this brings additional 3 questions:
1) how do I move rows 13 to 18 in mysql.cpp above the void (now its bool), because I wish to have some more functions but the data for login to DB stays the same...
I have tried to move them just above the void (bool) function, but error uncnown type name 'db' and if i moved it inside MySQL::MySQL(QObject *parent): then I am getting error use of undeclared identifier 'db'

"db" is currently a local variable.
If you move the block that defines that variable, then it is only valid in that new location.

What you want is a member variable, a variable that is valid in all methods of an object


class MySQL : public QObject
{
Q_OBJECT

// ...


private:
QSqlDataBase db;
}

Some very common coding convention prefix member variables with "m_" do make them clearly visible as such in the code


private:
QSqlDataBase m_db;




2) as soon as i request this function via MouseArea onclick, the whole application freezes for 3 sec till it return false as db unreachable (in case db is reachable, its just few milsec so its unnoticable). Is there anything what I can do? run the script on background or something?

Possible with multithreading, but then it gets much more complicated as everything becomes asynchronous.



3) can I somehow make a signal if connection status changes? so far I have timer that every 30 sec it will update and check if connection is available, but In case the status will changhe, is it possible that it will notify me myself like OnVariableChanges or something?

Not with the QSql API.
It might be possible to do that by polling, i.e. trying to open/close a test connection in regular intervals, or via the MySQL C-API.

Cheers,
_

shokarta
3rd April 2019, 12:54
For the point one, thank you, works beautyfuly!

For second point, can you provide any example? Not that it would be usefull here, but I also have on QML an icon indicator weather DB is online or not, this also freezes up the whole app if connection is not online, in here the multithreading would be awesome solution. Also is there somehow possible too give the whole app some Picture of loading while its freezed up because of this?

And for the third point, can you please provide an ylink for how its done in C API? I tried google it up, but no luck.

Thank you

shokarta
5th April 2019, 06:28
For second point, can you provide any example? Not that it would be usefull here, but I also have on QML an icon indicator weather DB is online or not, this also freezes up the whole app if connection is not online, in here the multithreading would be awesome solution. Also is there somehow possible too give the whole app some Picture of loading while its freezed up because of this?

I did figure out FastBlur + some PopUp with image... i set the raidus to something whenever its processing anythign with db, and back to 0 when its done...
This is good and usable... however the indicator of if db is online or not should be done on background as multithread, please share some link for this if you can :(

anda_skoa
5th April 2019, 08:51
Multithreading is quite complicated, a lot of possible errors if not handled correctly and very difficult to debug.

https://doc.qt.io/qt-5/examples-threadandconcurrent.html

How do the other programs that access the same database handle the case of it not being reachable?

Cheers,
_

shokarta
5th April 2019, 18:17
How do the other programs that access the same database handle the case of it not being reachable?

I dont understand the question, you mean this?:

MySQL::MySQL(QObject *parent) :
QObject(parent)
{
// Sets Termianl Database
terminal_db = QSqlDatabase::addDatabase("QMYSQL", "ExternalDB");
terminal_db.setHostName("localhost");
terminal_db.setDatabaseName("terminals");
terminal_db.setUserName("root");
terminal_db.setPassword("");
}

bool MySQL::checkConnection()
{
if(terminal_db.open()) { terminal_db.close(); return true; }
else { qDebug() << "Terminal DB Error: " << terminal_db.lastError().text(); return false; }
}

and the debug is:

Terminal DB Error: "Can't connect to MySQL server on 'localhost' (10061) QMYSQL: Nepoda?ilo se navázat spojení"
translation would be "Coulnd not establish the connection"

anda_skoa
6th April 2019, 09:25
I dont understand the question, you mean this?:


What I meant is this: you are running a database server and you likely do that because you have several programs connecting to it.
How do these other programs deal with the database server not running?

And which part of the system is responsible for starting the database server?
Why has it failed to do so when you are getting the connection error?

Cheers,
_

shokarta
6th April 2019, 09:35
OK, so this info is not realy relevant because:

the server is runing MySQL server as the main application if Attendence database (you swift you RFID user card and its recorded to db where its stored with your personal details - as every company has).

But I am developing a program on WinMate terminals, where you also swap your card, it reads its info and connect to this attendence DB and gets your personal info from the card ID, then save the record when you swifted to different mysql db...

therefore I need to check if I have available connection to db so I can save my record to outside mysql db, or to internal sqlite (and later save the records from sqlite to mysql)...

So, after all how other programs handle this is not relevant and available...

Lesiok
6th April 2019, 11:51
therefore I need to check if I have available connection to db so I can save my record to outside mysql db, or to internal sqlite (and later save the records from sqlite to mysql)...

You say about "outside database" : is localhost correct address ?

shokarta
6th April 2019, 12:15
for the testing yes, once the application is done, i will change the login data to the database to outside source...

Lesiok
6th April 2019, 14:30
Can You connect to database with this parameters and standard MySQL client ?