I have a problem with QT Creator.
I am writing a program and need a database for it.
I chose SQLITE and when I open the connection to the database directly in the MainWindow's constructor, everything is ok. But as soon as I use my class Database or methods from it, the connection to the database no longer works and I get the error
"Error open QSqlError("", "Driver not loaded", "Driver not loaded").
Does QtSql have problems with instances, methods or pointers?
I would be very grateful for tips, help or references to solutions, since I've been stuck for about 12 hours now.
my mainwindow.cpp when it works.
#include "HeaderLibary.h"
#include "ui_mainwindow.h"
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setMaximumHeight(MAX_WINDOW_HEIGHT);
this->setMinimumHeight(MIN_WINDOW_HEIGHT);
this->setMaximumWidth(MAX_WINDOW_WIDTH);
this->setMinimumWidth(MIN_WINDOW_WIDTH);
QFont font;
font.setPixelSize(FONT_SIZE);
font.setBold(true);
font.setFamily(FONT_FAMILY);
QString buffer;
QGridLayout *windowLayout = new QGridLayout;
matrix *inputMatrix = new matrix("input",MAXLENGTH,false,QLINEEDIT_HEIGHT,QLINEEDIT_WIDTH,font,5,5,true,1);
inputMatrix->set_matrix();
this->inputWidgets = inputMatrix->getMatrixWidgets();
buffer = "Hello User, welcome to AES - Advanced Encryption Standard!";
QLabel *title = inputMatrix->setLabel(buffer,MAX_WINDOW_WIDTH,LABEL_HIGHT);
font.setPointSize(FONT_SIZE_TEXT);
buffer = "With AES you can encrypt messages of up to 16 characters or 16 Bytes."
"\n\nPlease enter your message in this matrix. One character per field in numbered order.";
QLabel *text = inputMatrix->setLabel(buffer,MAX_WINDOW_WIDTH,LABEL_HIGHT);
QPushButton *startBtn = inputMatrix->setButton("Start",BTN_WIDTH,BTN_HEIGHT);
connect(startBtn,SIGNAL(clicked()),this,SLOT(start_clicked()));
windowLayout->addWidget(title,0,0,1,2,Qt::AlignCenter);
windowLayout->addWidget(text,1,0,1,2,Qt::AlignCenter);
windowLayout->addLayout(inputMatrix->getLayout(),2,0,1,2,Qt::AlignCenter);
windowLayout->addWidget(startBtn,3,1,1,1,Qt::AlignRight);
QWidget *widget = new QWidget();
widget->setLayout(windowLayout);
setCentralWidget(widget);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("AES_DB.db");
if(!db.open())
qDebug()<< db.lastError();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::start_clicked()
{
QSqlDatabase db;
QSqlQuery qry;
QString tableName = "orginalMsgLetters";
QString buffer= QString("DROP TABLE %1;").arg(tableName);
if(!qry.exec(buffer))
qDebug()<< qry.lastError();
buffer = QString("CREATE TABLE IF NOT EXISTS %1 (id INTEGER NOT NULL PRIMARY KEY, itemValue VARCHAR(20));").arg(tableName);
if(!qry.exec(buffer))
qDebug()<< qry.lastError();
bool check = false;
int index = 0;
while(!check){
if(inputWidgets->at(index)->text() == ""){
QMessageBox::information(this,tr("Error"), tr("Please fill out each box to continue"));
return;
}
else if(inputWidgets->at(index)->text() == "ü" || inputWidgets->at(index)->text() == "ä" || inputWidgets->at(index)->text() == "ö" || inputWidgets->at(index)->text() == "ß"){
QMessageBox::information(this,tr("Error"), tr("Please don't use Ü/ü, Ä/ä, Ö/ö or ß "));
return;
}
else {
if(index+1 == MAXLENGTH)
check = true;
else
index++;
}
}
for (int i = 0; i < MAXLENGTH; ++i) {
buffer=QString("INSERT INTO %1 (id,itemValue)VALUES (%2,%3);").arg(tableName).arg(i).arg(this->inputWidgets->at(i)->text());
if(!qry.exec(buffer))
qDebug()<<qry.lastError();
buffer=QString("SELECT * FROM %1 WHERE id=%2").arg(tableName).arg(i);
if(!qry.exec(buffer))
qDebug()<<qry.lastError();
while(qry.next())
qDebug()<< qry.value(1).toString();
}
db.close();
}
my mainwindow.h
#pragma once
#include "HeaderLibary.h"
#include "Config_File.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QList<QLineEdit*>* inputWidgets;
//Database *db = new Database();
QSqlDatabase *db = new QSqlDatabase;
QSqlQuery *qry = new QSqlQuery;
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void start_clicked();
private:
Ui::MainWindow *ui;
};
my Database.cpp
When I use any method of this in my mainwindow.cpp to initialize the database it won't work and i get the error."Driver not loaded"
#include "database.h"
Database::Database(){
}
Database::~Database(){
}
void Database::deleteTable(QString tableName){
QSqlQuery qry;
QString buffer = QString("DROP TABLE %1;").arg(tableName);
qry.prepare(buffer);
qry.exec();
}
void Database::connect(){
QSqlDatabase db;
db.addDatabase("QSQLITE");
db.setDatabaseName("AES_DB.db");
if(!db.open())
qDebug()<< "Error open "<< db.lastError();
}
void Database::addValueToTable(QString tableName,int id, QString value){
QSqlQuery qry;
QString buffer = QString("INSERT INTO %1 (id,itemValue)VALUES (%2,%3);").arg(tableName).arg(id).arg(value);
qry.prepare(buffer);
if(!qry.exec()){
qDebug()<< qry.lastError();
qDebug()<< "\n insert Error \n";
}
}
void Database::createTable(QString tableName){
QSqlQuery qry;
QString buffer = QString("CREATE TABLE IF NOT EXISTS %1 (id INTEGER NOT NULL PRIMARY KEY, itemValue VARCHAR(20));").arg(tableName);
if(!qry.exec(buffer)){
qDebug()<< qry.lastError();
qDebug()<< "\n create Error \n";
}
}
void Database::close(){
QSqlDatabase db;
db.close();
}
QString Database::getValueFromTable(QString tableName,int id){
QSqlQuery qry;
QString string = QString("SELECT * FROM %1 WHERE id=%2").arg(tableName).arg(id);
qry.prepare(string);
if(!qry.exec(string)){
qDebug()<< qry.lastError();
qDebug()<< "\n get Error \n";
}
while(qry.next())
return qry.value(1).toString();
}
My database.h
#pragma once
#include "Config_File.h"
#include "HeaderLibary.h"
class Database
{
private:
public:
Database();
~Database();
void connect();
void addValueToTable(QString tableName,int id, QString value);
void deleteTable (QString tableName);
void createTable(QString tableName);
QString getValueFromTable(QString tableName,int id);
void close();
};
'''
[1]: https://i.stack.imgur.com/48zP0.png
Why don't you use
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("AES_DB.db");
...in your Database::connect() method?
Related
I'm experimenting with QThreadPool and realized that my program exited with SIGSEGV after QThreadPool reaches expiry timeout.
I started the program creating pointers to QLabel and QLineEdits as placeholders, which are kept in QLists.
Then, the method carregar2() is called, when the menu is clicked, to start the QThreadPool.
I implemented 4 QRunnables. They're all the same: they invoke external program (QProcess) with different parameters. Their result are written to QLineEdits.
If I set setExpiryTimeout(-1), the program does not crash.
This is the MainWindow class, it is the called from the main.cpp :
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtWidgets>
#include "ClickableLabel.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QMainWindow::showMaximized();
ui->setupUi(this);
QStringList args = QApplication::arguments();
QString path;
if(args.size()<=1)
path = QFileDialog::getExistingDirectory(parent, "", "/studio/FOTOS", QFileDialog::ShowDirsOnly);
else
path = static_cast<QString>(args.at(1));
QDir *dir = new QDir(path);
setWindowTitle("QExif - " + path);
QScrollArea *scroll = new QScrollArea();
QGridLayout *grid = new QGridLayout(scroll);
QFrame *frame = new QFrame();
int row=0;
int col=0;
QStringList filtro;
filtro << "*.jpg";
const QFileInfoList fil = dir->entryInfoList(filtro,QDir::Files );
qDebug() << "FOTOS: " << fil.size();
foreach (QFileInfo fi, fil ) {
QString f = fi.absoluteFilePath();
QLabel *l = new ClickableLabel(); //A custom QLabel that implements a clicked() signal and "emit clicked()" on mousePressEvent
l->setStyleSheet("border: 5px solid white");
l->setMaximumSize(w,h);
l->setMinimumSize(w,h);
l->setProperty("foto", f);
l->setToolTip(f);
connect(l, SIGNAL(clicked()), this, SLOT(abrirVisualizadorExterno()));
grid->addWidget(l,row,col,1,1,Qt::AlignTop);
//tag buttons
QHBoxLayout *box = new QHBoxLayout(parent);
QFrame *btnFrame = new QFrame();
btnFrame->setLayout(box);
btnFrame->setMaximumWidth(w);
QLineEdit *tagArtista = new QLineEdit(parent);
tagArtista->setToolTip("Etiquetas");
grid->addWidget(tagArtista,row+1,col,1,1,Qt::AlignTop);
QLineEdit *tagDescricao = new QLineEdit(parent);
tagDescricao->setToolTip("Descrição da imagem");
grid->addWidget(tagDescricao,row+2,col,1,1,Qt::AlignTop);
QLineEdit *tagDataHora = new QLineEdit(parent);
tagDataHora->setToolTip("Data e Hora");
grid->addWidget(tagDataHora,row+3,col,1,1,Qt::AlignTop);
tagArtista->setProperty("foto", f);
tagDescricao->setProperty("foto", f);
tagDataHora->setProperty("foto", f);
fList->append(f);
labelList->append(l);
tagList->append(tagArtista);
descricaoList->append(tagDescricao);
dataHoraList->append(tagDataHora);
col++;
if(col >3) { col=0; row+=4; }
} //foreach
frame->setLayout(grid);
scroll->setWidget(frame);
setCentralWidget(scroll);
/*
* MENU
* */
QMenu *menuExif = ui->menuBar->addMenu("Exif");
menuExif->addAction("Carregar");
connect(menuExif,SIGNAL(triggered(QAction*)),this,SLOT(menuHandler(QAction*)));
}
void MainWindow::menuHandler(QAction *action){
if(action->text() == "Carregar"){
carregar2();
}
}
void MainWindow::carregar2(){
QThreadPool *pool = QThreadPool::globalInstance();
pool->setExpiryTimeout(-1);
for(int i=0; i<fList->count(); i++){
ImagemRunnable *imageRunnable = new ImagemRunnable(labelList->at(i), fList->at(i), w, h);
QThreadPool::globalInstance()->start(imageRunnable);
TagRunnable *tagRunnable = new TagRunnable(tagList->at(i), fList->at(i));
pool->start(tagRunnable);
TagDescricaoRunnable *tagDescricaoRunnable = new TagDescricaoRunnable(descricaoList->at(i), fList->at(i));;
pool->start(tagDescricaoRunnable);
TagDataHoraRunnable *tagDataHoraRunnable = new TagDataHoraRunnable(dataHoraList->at(i), fList->at(i));
pool->start(tagDataHoraRunnable);
}
}
void MainWindow::abrirVisualizadorExterno(){
ClickableLabel *l = (ClickableLabel *) sender();
qDebug() << "Abrir" << l->property("foto");
if (l->property("foto").isValid()){
QStringList cmd;
cmd << QString("eog %1").arg(l->property("foto").toString());
system(cmd.at(0).toUtf8().data());
}
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event){
qDebug() << watched->property("foto").toString();
return false;
}
MainWindow::~MainWindow()
{
delete ui;
}
And this is one of the implemented QRunnables:
header:
#ifndef TAGRUNNABLE_H
#define TAGRUNNABLE_H
#include <QRunnable>
#include <QLineEdit>
class TagRunnable : public QRunnable, QObject
{
public:
TagRunnable(QLineEdit * f, QString file);
void run() override;
private:
QLineEdit *field;
QString file;
};
#endif // TAGRUNNABLE_H
cpp:
#include "tagrunnable.h"
#include <QProcess>
#include <QDebug>
TagRunnable::TagRunnable(QLineEdit * f, QString file)
{
field = f;
this->file = file;
}
void TagRunnable::run(){
QProcess *proc = new QProcess();
//pessoas na foto
proc->start("/usr/bin/exif", QStringList()
<< "-t" << "0x013b"
<< "-m"
<< file
);
if(!proc->waitForFinished()){
qDebug() << "Timeout ao ler exif tag (pessoas)." << file;
}
field->setText(proc->readAllStandardOutput());
field->setProperty("tagOriginal", field->text());
}
My questions:
Suppose I use 30 seconds as expiry timeout. After that time, is my reference to the QProcess removed from memory and causing the QLineEdit text to be lost as well?
Is it ok to set expiry timeout to -1 in any situation or, perhaps, I'm not using it properly because of other architectural error of my program ?
disclaimer: I'm sorry if the code is not neatly indented. know some may be irked at this.
I'm using qt5
I have two .cpp(register_user.cpp and parking.cpp) files that will connect to a database. I tried to connect register_user.cpp to the database and it works perfectly fine. It is connected and the sql commands work fine. Tut, I need to also connect another file which is the parking.cpp to the database. I connected parking.cpp to the database and then checked for the connection. it said that it is connected but the sql commands don't work.
How can I connect the second file to the database correctly?
login.h
#ifndef LOGIN_H
#define LOGIN_H
#include <QMainWindow>
#include <QtSql>
#include <QDebug>
#include <QFileInfo>
#include <main_interface.h>
namespace Ui {
class Login;
}
class Login : public QMainWindow
{
Q_OBJECT
public:
QSqlDatabase mydb;
void connClose()
{
mydb.close();
mydb.removeDatabase(QSqlDatabase::defaultConnection);
}
bool connOpen()
{
mydb=QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("C:/SQLite/sqlite-tools-win32-x86-3250200/IPark.db");
if(!mydb.open())
{
qDebug()<<("Failed to open database");
return false;
}
else
{
qDebug()<<("Connected. . .");
return true;
}
}
public:
explicit Login(QWidget *parent = 0);
~Login();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::Login *ui;
};
#endif // LOGIN_H
register_user.h
#ifndef REGISTER_USER_H
#define REGISTER_USER_H
#include <QDialog>
#include "login.h"
namespace Ui {
class register_user;
}
class register_user : public QDialog
{
Q_OBJECT
public:
Login conn;
explicit register_user(QWidget *parent = 0);
~register_user();
private slots:
void on_pushButton_clicked();
private:
Ui::register_user *ui;
};
#endif // REGISTER_USER_H
register_user.cpp
#include <login.h>
#include "login.h"
#include "register_user.h"
#include "ui_register_user.h"
#include <QMessageBox>
register_user::register_user(QWidget *parent) :
QDialog(parent),
ui(new Ui::register_user)
{
ui->setupUi(this);
if(!conn.connOpen())
ui->label_reg->setText("Failed to open database");
else
ui->label_reg->setText("Connected. . .");
}
register_user::~register_user()
{
delete ui;
}
void register_user::on_pushButton_clicked()
{
Login conn;
QString username, plate_number, name;
username=ui->lineEdit_Username->text();
plate_number=ui->lineEdit_Plate_Number->text();
name=ui->lineEdit_Name->text();
QSqlQuery qry;
qry.prepare("insert into User(User_id, plate_number, name, spot_number, credit, order_id) values('"+username+"','"+plate_number+"','"+name+"',NULL, NULL, NULL)");
if(qry.exec()){
QMessageBox::critical(this, tr("SAVE"), tr("SAVED"));
}
conn.connClose();
}
parking.h
#ifndef PARKING_H
#define PARKING_H
#include <QDialog>
#include "login.h"
namespace Ui {
class parking;
}
class parking : public QDialog
{
Q_OBJECT
public:
Login conn;
explicit parking(QWidget *parent = 0);
~parking();
private slots:
void on_ParkSpace100_clicked();
void on_ParkSpace101_clicked();
void on_ParkSpace102_clicked();
void on_ParkSpace103_clicked();
private:
Ui::parking *ui;
};
#endif // PARKING_H
parking.cpp
#include <login.h>
#include "login.h"
#include "parking.h"
#include "ui_parking.h"
#include "reservation.h"
#include <QMessageBox>
int status = 0;
parking::parking(QWidget *parent):
QDialog(parent),
ui(new Ui::parking)
{
ui->setupUi(this);
Login conn;
if(!conn.connOpen())
ui->label->setText("Failed to open database");
else
ui->label->setText("Connected. . .");
}
parking::~parking()
{
delete ui;
}
void parking::on_ParkSpace100_clicked()
{
Login conn;
QSqlQuery qry;
qry.prepare("insert into User(User_id, plate_number, name, spot_number, credit, order_id) values('105,0123,'Amethyst',NULL, NULL, NULL)");
if(qry.exec()){
QMessageBox::warning(this, tr("SAVE"), tr("SAVED"));
}
}
void parking::on_ParkSpace101_clicked()
{
Login conn;
QSqlQuery qry;
conn.connOpen();
qry.prepare("select name from User where spot_number = 101");
bool value = qry.exec();
if(value == true)//true : then someone is on the spot
{
conn.connClose();
QMessageBox::warning(this, "Error", "Someone's already in the spot");
qDebug("Inside ParkSpace101");
}
hide();
Reservation b;
b.setModal(true);
b.setWindowTitle("Reservation Page");
b.exec();
}
void parking::on_ParkSpace102_clicked()
{
QMessageBox::warning(this,"WARNING", "Someone's already in the spot.");
}
void parking::on_ParkSpace103_clicked()
{
Login conn;
QSqlQuery qry;
conn.connOpen();
qry.prepare("select name from User where spot_number = 101");
bool value = qry.exec();
if(value == true)//true : then someone is on the spot
{
conn.connClose();
QMessageBox::warning(this, "Error", "Someone's already in the spot");
qDebug("Inside ParkSpace101");
}
hide();
Reservation b;
b.setModal(true);
b.setWindowTitle("Reservation Page");
b.exec();
}
You'll want to pass a unique connectionName into the second argument in QSqlDatabase::addDatabase() in the connOpen method of login.h. This will allow you to add a new database connection while keeping the old one runnning.
Thus the line with addDatabase() should resemble
mydb = QSqlDatabase::addDatabase("QSQLITE", your_connection_name_here);
Make sure that the connectionName is different for register_user and parking. My suggestion is to pass the connectionName as a parameter into the constructor of Login. Then store this into a member variable.
explicit Login(const QString &connectionName, QWidget *parent = 0);
And modify the QSqlDatabase functions to handle the member variable
mydb.removeDatabase(m_connectionName);
...
mydb = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
When you initiate Login in register_user and parking, you can pass in your own connection name.
Login conn("register_user_sqlite_connection");
If you dislike passing arguments into the constructor, an alternative is to have a setter function for the connectionName.
void setConnectionName(const QString &connectionName);
then call it right after you initiate Login in register_user and parking.
Login conn;
conn.setConnectionName("register_user_sqlite_connection");
Further Reading: http://doc.qt.io/qt-5/qsqldatabase.html#addDatabase
Edit:
Minimal Example of Why OP's Code Does Not Work
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
class Login
{
public:
QSqlDatabase mDatabase; // Bad practice: don't use as class member.
// Read more: http://doc.qt.io/qt-5/qsqldatabase.html#details
Login() {}
bool connOpen()
{
// Only the default connection is used.
mDatabase = QSqlDatabase::addDatabase("QSQLITE");
mDatabase.setDatabaseName("stackOverflow.db");
if(!mDatabase.open())
{
qDebug() << ("Failed to open database");
return false;
}
qDebug() << "Connected. . .";
return true;
}
QSqlQuery exec(const QString& query)
{
return mDatabase.exec(query);
}
};
class RegisterUser
{
public:
Login conn;
RegisterUser()
{
qDebug() << "Opening database from RegisterUser()";
bool ok = conn.connOpen();
if (ok) qDebug() << "Connection success!";
else qDebug() << "Connection error...";
}
};
class Parking
{
public:
Login conn;
Parking()
{
qDebug() << "Opening database from Parking()";
bool ok = conn.connOpen();
if (ok) qDebug() << "Connection success!";
else qDebug() << "Connection error...";
}
};
int main()
{
// Initialise with default connection. 😁😁😁
RegisterUser reg;
// Opening database from RegisterUser()
// Connected. . .
// Connection success!
qDebug() << reg.conn.exec("SELECT 1").executedQuery();
// "SELECT 1"
// STEALS the default connection!!! 😡😡😡
Parking par;
// Opening database from Parking()
// QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
// QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
// Connected. . .
// Connection success!
// Query from RegisterUser failed because it's not connected!!! 😱😱😱
qDebug() << reg.conn.exec("SELECT 1").executedQuery();
// QSqlQuery::exec: database not open
// ""
qDebug() << par.conn.exec("SELECT 1").executedQuery();
// "SELECT 1"
return 0;
}
This is from my previous question of read the text line by line.
Based from #KubaOber answer, I can successfully read and display the content line by line in a certain time interval.
Then, I was trying to transmit the content of the text file serially into Arduino Uno using the source code available on the internet.
Here's the header code:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtSerialPort/QSerialPort>
#include <QSerialPortInfo>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
QSerialPort *arduino;
static const quint16 arduino_uno_vendor_id = 10755;
static const quint16 arduino_uno_product_id = 67;
QString arduino_port_name;
bool arduino_is_available;
QByteArray serialData;
QString serialBuffer;
void updateSpeedometer(QString);
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
Ui::Widget *ui;
private slots:
private:
};
#endif // WIDGET_H
and here's the main.cpp :
#include <QtWidgets>
#include <QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
#include "widget.h"
#include <QDebug>
bool arduino_is_available = false;
QString arduino_port_name = "";
QSerialPort *arduino = new QSerialPort;
QString serialBuffer = "";
static const quint16 arduino_uno_vendor_id = 10755;
static const quint16 arduino_uno_product_id = 67;
class PeriodicReader : public QObject {
Q_OBJECT
QTimer m_timer{this};
QFile m_file{this};
void readLine() {
if (m_file.atEnd()) {
m_timer.stop();
return;
}
QByteArray lineBaru(m_file.readLine());
emit newLine(lineBaru);
qDebug()<<lineBaru;
QString lineString(lineBaru);
qDebug()<<lineString << " converted to QString";
lineString.remove("\n");
qDebug()<<lineString;
lineString.remove(" ");
qDebug()<<lineString;
QRegExp rx("d(\\d+)");
QList<int> list;
int pos = 0;
while ((pos = rx.indexIn(lineString, pos)) != -1) {
list << rx.cap(1).toInt();
pos += rx.matchedLength();
}
qDebug()<<list;
int listi = list.at(0);
qDebug()<<"list[0] :"<<listi;// <<---THIS IS WHERE I CAN GET THE VALUE AFTER THE "d"
updateSpeedometer(lineString);
}
void updateSpeedometer(QString command)
{
if(arduino->isWritable())
{
command.remove(" ");
arduino->write(command.toStdString().c_str());
qDebug() << command.toStdString().c_str() << " is uploaded to Arduino";
}else{
qDebug()<<"Couldn't write to Serial !" ;
}
}
public:
explicit PeriodicReader(QObject * parent = {}) : QObject(parent) {
connect(&m_timer, &QTimer::timeout, this, &PeriodicReader::readLine);
}
void load(const QString & fileName) {
m_file.close(); // allow re-opening of the file
m_file.setFileName(fileName);
if (m_file.open(QFile::ReadOnly | QFile::Text)) {
readLine();
m_timer.start(1000); // <<<---------------HERE IS WHERE I WANT THE DELAY TO BE
}
}
Q_SIGNAL void newLine(const QByteArray &);
};
QString lineToString(QByteArray line)
{
while (line.endsWith('\n') || line.endsWith('\r'))
line.chop(1);
return QString::fromUtf8(line);
}
int main(int argc, char ** argv) {
qDebug()<<"Number of available ports :" <<QSerialPortInfo::availablePorts().length();
foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
qDebug()<<"Has Vendor ID:" << serialPortInfo.hasVendorIdentifier();
if(serialPortInfo.hasVendorIdentifier()){
qDebug()<<"Vendor ID:"<< serialPortInfo.vendorIdentifier();
}
qDebug()<<"Has Product ID:" << serialPortInfo.hasProductIdentifier();
if(serialPortInfo.hasProductIdentifier()){
qDebug()<<"Product ID:"<< serialPortInfo.productIdentifier();
}
}
foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
if(serialPortInfo.hasVendorIdentifier() && serialPortInfo.hasProductIdentifier()){
if(serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id){
if(serialPortInfo.productIdentifier() == arduino_uno_product_id){
arduino_port_name = serialPortInfo.portName();
arduino_is_available = true;
}
}
}
}
if(arduino_is_available){
//open and configure the serialport
arduino->setPortName(arduino_port_name);
arduino->open(QSerialPort::ReadWrite);
arduino->setBaudRate(QSerialPort::Baud9600);
arduino->setDataBits(QSerialPort::Data8);
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
arduino->setFlowControl(QSerialPort::NoFlowControl);
//QObject::connect(arduino,SIGNAL(readyRead()),this,SLOT(readSerial()));
}else{
//show error message
qDebug()<<" Port Error, Couldn't find the Arduino' !";
// QMessageBox::warning(this, "Port Error, Couldn't find the Arduino !");
}
QApplication app{argc, argv};
QWidget window;
QVBoxLayout layout{&window};
QPushButton load{"Load"};
QPlainTextEdit edit;
layout.addWidget(&load);
layout.addWidget(&edit);
window.show();
PeriodicReader reader;
QObject::connect(&load, &QPushButton::clicked, [&]{
auto name = QFileDialog::getOpenFileName(&window);
if (!name.isEmpty()) {
edit.clear(); // allow re-opening of the file
reader.load(name);
}
});
QObject::connect(&reader, &PeriodicReader::newLine, &edit,
[&](const QByteArray & line){ edit.appendPlainText(lineToString(line)); });
return app.exec();
}
#include "main.moc"
It is from the coding of "reading text line by line" I've asked months a go which I include the arduino serial connection coding as well and hey, it worked!
It reads the text line by line and when each line is displayed in textEdit, it also transmitted to Arduino Uno.
So my request is, instead of the delay between line by line is preset at 2 seconds, can the delay duration be controlled by the content of the text file?
Let say.. the first line content inside the text file is 's200 d300' , and the 's200' is processed by arduino to generate a frequency, meanwhile 'd300' is the delay interval in milliseconds before it reads the next line and generate another frequency signal.
So,how to make Qt recognise the 'd300' and use it as the delay value?
QString str = "asa24fsesfd300kslfv0";
QTextDocument document(str);
QTextCursor d = document.find("d");
qDebug()<<d.position();
QString s = str.mid(d.position()-1,6); // How many digits can be after << d >>
int count = 0;
for (int i = 1; i < s.size(); ++i) {
QString d = s.at(i);
if(d.isEmpty()){
break;
}else{
bool ok;
int k = d.toInt(&ok);
if(ok){
count++;
}else{
break;
}
}
}
QString result = str.mid(d.position(),count);
bool ok;
int result_int = result.toInt(&ok);
if(ok){
qDebug()<< result_int;
}
result 300
I have written code for a server which accepts connections from different clients. Each client is serviced in different threads. Each thread accesses a database to get data and then updates this data to all the clients connected to server.
1) For the first time when UI asks data from server, it responds properly, but after that server does not read the socket i.e. Server's readyread() doesn't get invoked. Funnily enough, this works fine in mac and linux, this issue is seen only on windows
2) I was able to verify that when the DB module emits a signal which is caught by the threads, the hang occurs, Because everything worked fine when I removed the emit.
Here, I am attaching all the needed .h and .cpp codes
Defn.h
#ifndef DEFN_H
#define DEFN_H
struct PresetData{
QString ID;
QString name;
QString value;
QString source;
};
#endif // DEFN_H
main.cpp
#include <QCoreApplication>
#include "myserver.h"
#include "mydb.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyDB db;
MyServer server(&db);
server.startServer();
return a.exec();
}
mydb.h
#ifndef MYDB_H
#define MYDB_H
#include <QObject>
#include <QtSql>
#include "Defn.h"
class MyDB : public QObject
{
Q_OBJECT
public:
explicit MyDB(QObject *parent = 0);
signals:
void dataAvailable(QString ID, QString name, QString value, QString source);
public slots:
void onUpdateData(QString ID, QString name, QString value, QString source);
void onGetData(QString ID, QString name, QString value, QString source);
private:
QSqlDatabase m_db;
};
#endif // MYDB_H
mydb.cpp
#include "mydb.h"
MyDB::MyDB(QObject *parent) :
QObject(parent)
{
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setConnectOptions();
m_db.setDatabaseName("D:/MySimulator/New Folder/TCPServer1/DB.db");
if (m_db.open()){
qDebug() << "DB opened succesfully" ;
}else{
qDebug() << "DB Opening failed" ;
}
QStringList tables = m_db.tables();
if (tables.contains("Presets", Qt::CaseInsensitive)){
qDebug() << "DB Contains Data" ;
return;
}
}
void MyDB::onGetData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onGetData" ;
QString queryString = "SELECT Value from 'Presets' where ID = \'" + ID + "\'";
QSqlQuery q;
bool result = q.exec(queryString);
if (result){
if (q.next()){
value = q.value(q.record().indexOf("Value")).toString();
qDebug() << " Retrieved Value = " << value ;
emit dataAvailable(ID, name, value, source);
}else{
qDebug("Empty Result");
}
}else{
qDebug("NO Result");
}
}
void MyDB::onUpdateData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onUpdateData" ;
QString queryString = "UPDATE 'Presets' SET Value = \'" + value + "'\ WHERE ID = \'" + ID + "\'";
QSqlQuery q;
QSqlDatabase::database().transaction();
bool result = q.exec(queryString);
if (result){
QSqlDatabase::database().commit();
onGetData(ID, name, "", "000");
}else{
qDebug("NO Result");
}
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QDebug>
#include "Defn.h"
#include "mydb.h"
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(int ID, MyDB* db, QObject * parent = 0);
void run();
void parseInput(QString string);
signals:
void error(QTcpSocket::SocketError socketError);
void updateData(QString ID, QString name, QString value, QString source);
void getData(QString ID, QString name, QString value, QString source);
public slots:
void readyRead();
void disconnected();
void onDataAvailable(QString ID, QString name, QString value, QString source);
private:
QTcpSocket* socket;
int socketDescriptor;
MyDB* db;
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include "qtcpserver.h"
#include "qabstractsocket.h"
MyThread::MyThread(int ID, MyDB* db, QObject * parent ):
QThread(parent)
{
this->socketDescriptor = ID ;
this->db = db;
}
void MyThread::run()
{
// thread starts here.
qDebug() << socketDescriptor << "Starting Thread" ;
socket = new QTcpSocket();
if (!socket->setSocketDescriptor(this->socketDescriptor)){
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
connect(this, SIGNAL(getData(QString, QString , QString , QString )), this->db, SLOT(onGetData(QString , QString , QString , QString )));
connect(this, SIGNAL(updateData(QString , QString , QString , QString )), this->db, SLOT(onUpdateData(QString , QString , QString , QString )));
connect(this->db, SIGNAL(dataAvailable(QString , QString , QString , QString )), this, SLOT(onDataAvailable(QString , QString , QString , QString )));
qDebug() << socketDescriptor << "Client Connected" ;
exec();
}
void MyThread::readyRead()
{
QByteArray data = socket->readAll();
qDebug() << socketDescriptor << "Data in: " << data;
parseInput(data);
}
void MyThread::disconnected()
{
qDebug() << socketDescriptor << "Disconnected" ;
socket->deleteLater();
exit(0);
}
void MyThread::parseInput(QString dataFromTCP)
{
qDebug() << socketDescriptor << ":" <<"parseInput " << dataFromTCP;
if (dataFromTCP.isEmpty())
return;
QStringList list1 = dataFromTCP.split("\n", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list1 BEGIN";
for (int i = 0 ; i < list1.count(); i++)
{
qDebug() << i<< ":" << list1.at(i);
}
qDebug() << socketDescriptor << ":" << "list1 END";
if (list1.count() < 1){
return;
}
QString strMessage = "";
for (int i = 0 ; i < list1.count() ; i++)
{
strMessage = list1[i];
QStringList list2 = strMessage.split(" ", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list2 BEGIN";
for (int i = 0 ; i < list2.count(); i++)
{
qDebug() << i<< ":" << list2.at(i);
}
qDebug() << socketDescriptor << ":" << "list2 END";
if (list2.count() < 1){
break;
}
QString ID = list2[1];
QString source = QString::number(socketDescriptor) ;
if (list2[0] == "GET"){
emit getData(ID, "", "", source);
}
else if (list2[0] == "UPD"){
QString value = list2[2];
emit updateData(ID, "", value, source);
}
}
}
void MyThread::onDataAvailable(QString ID, QString name, QString value, QString source)
{
if( (QString::number(socketDescriptor) == source) || ("000" == source ) ) {
qDebug() << socketDescriptor << " : On Data Available " << ID << name << value ;
QString data = "DATA " + ID + " " + value + " " + "\n" ;
QByteArray ba;
ba.append(data);
socket->write(ba);
}
}
myserver.h
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QDebug>
#include <QObject>
#include <QTCPServer>
#include <QTCPSocket>
#include "mythread.h"
#include "mydb.h"
class MyServer: public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(MyDB* pdb, QObject* parent = 0);
void startServer();
signals:
public slots:
protected:
void incomingConnection(qintptr socketDescriptor);
private:
MyDB* pdb ;
};
#endif // MYSERVER_H
myserver.cpp
#include "myserver.h"
MyServer::MyServer(MyDB* pdb, QObject* parent ):
QTcpServer(parent)
{
this->pdb = pdb;
}
void MyServer::startServer()
{
if (!this->listen(QHostAddress::Any, 1234)){
qDebug() << "Could not Start Server " << this->errorString();
}
else{
qDebug() << " Server Running... ";
}
}
void MyServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting... ";
MyThread *thread = new MyThread(socketDescriptor, pdb, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
Here the signal about which I mentioned above is dataAvailable from "mydb.cpp". If I comment out that line then server responds to client messages. But if that signal is emitted then after the initial response, the server seems to hang and no longer reacts to incoming messages from the client.
The same code is working perfectly fine in mac and linux. But it is having this problem in Windows only.
Could someone let me know what is it that I am doing wrong that it is failing only in Windows?
Thanks in advance for helping me out.
EDIT:
The objective of this code is that whenever a thread causes an update call to the database, EVERY thread including the one that called the update gets informed about the change. So it is EXPECTED that other thread that runs at that time also receives a signal.
This is what is expected of the server:
Be able to allow TCP connections from multiple clients simultaneously.
If any client requests info, it gets the required data over the TCP connection.
If any client updates info, all clients including the updating client, gets a notifications over the TCP connection.
Well, for starters, your code is completely not thread-safe. You create a single instance of MyDB in your main() function, then call it from threads without protecting its data member. Also, signals get emitted, updating data without any protection. What if two threads happen to be running at the same time?
Secondly, and this is more important: whenever you emit dataAvailable() you call functions in other thread objects in your own thread. This is the code path when data arrives:
MyThread::parseInput() emits
MyThread::getData(), which is connected to
MyDB::onGetData(), which emits
MyDb::dataAvailable, which is connected to (drumroll....)
MyThread::onDataAvailable, which eventually calls
socket->write()
So if data arrives in thread #1, you're going to send data from MyThread object #2, #3, #4, etc from .... thread #1. Depending on the OS, this is bad news. I don't know enough about Windows threads but I do know this code is terminally broken.
If all you want to do is update a database and relay the data you can dispense with the threads and use a sequential program that handles sockets using the regular Qt signals and slots just fine.
I tried to outsource the code for the connection to a local PostgreSQL server from my "main.cpp" file into a seperate class called "database.cpp".
The connection worked just fine, when I had the code in the "main.cpp":
main.cpp
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
QSqlQuery query(db);
qint32 declareConnection()
{
db.setHostName("127.0.0.1");
db.setPort(5432);
db.setDatabaseName("postgres");
db.setUserName("postgres");
db.setPassword("password");
return 0;
}
qint32 createUser(QString username, QString password)
{
if (db.open())
{
db.transaction();
query.prepare("INSERT INTO users (name, password) VALUES (?, ?);");
query.bindValue(0, username);
query.bindValue(1, toMD5(password));
query.exec();
query.finish();
db.commit();
db.close();
}
return 0;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Declare Database: " << declareConnection();
qDebug() << "Create User: " << createUser("Testuser", "Testpassword");
return a.exec();
}
But after I put the functions in the "database.cpp", the prepare.query() fails every time I try to execute it.
Here's my current code:
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Database postgre;
qDebug() << "Declare Database: " << postgre.declareConnection();
qDebug() << "Create User: " << postgre.createUser("Testuser", "Testpassword");
return a.exec();
}
Database.h
class Database : public QObject
{
Q_OBJECT
public:
explicit Database(QObject *parent = 0);
qint32 declareConnection();
qint32 createUser(QString username, QString password);
QSqlDatabase db();
};
Database.cpp
QSqlDatabase Database::db()
{
return QSqlDatabase::database();
}
qint32 Database::declareConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName("127.0.0.1");
db.setPort(5432);
db.setDatabaseName("postgres");
db.setUserName("postgres");
db.setPassword("password");
return 0;
}
qint32 Database::createUser(QString username, QString password)
{
if (db().open())
{
db().transaction();
QSqlQuery query(db());
query.prepare("INSERT INTO users (name, password) VALUES (?, ?);");
query.bindValue(0, username);
query.bindValue(1, toMD5(password));
query.exec();
query.finish();
db().commit();
db().close();
}
return 0;
}
The declaration of the database seems to work just fine, but when it comes to the "createUser()" function, there is always that problem with the "query.prepare()" command.
The database is open, so that works.
Also the transaction is in an open state, when I check in debug.
The prepare is false.
The query.exec() says: Syntaxerror at end of line LINE 1: EXECUTE ^.
QPSQL: Unable to create query.
WARNING: No open transaction. (But was open???)
The problem is here
void Database::declareConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
you declared local variable db on a stack.
The decision is:
class Database : public QObject
{
...
QSqlDatabase & db() { return m_db; }
private:
QSqlDatabase m_db;
};
void Database::declareConnection()
{
m_db = QSqlDatabase::addDatabase("QPSQL");
...
}