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;
}
Related
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?
I trying to change my code to save recordings to wav-files. Later i have to import this to MATLAB.
Its works to save like .*pcm or.*wav. But I want play it with (example VLC Player) external player.
QAudioFormat format;
Conf values;
format.setSampleRate(values.getSampRate());
format.setChannelCount(values.getChannel());
format.setSampleSize(values.getSampSize());
format.setCodec(values.getCodec());
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
in config-file i have configuration:
samp_rate=88200
channel=1
samp_size=24
codec=Audio/PCM
byte_order=QAudioFormat::LittleEndian
sample_type=QAudioFormat::SignedInt
Saving file looks:
m_audio->startrecording(fn+".pcm");
I changed pcm to wav - file will be recorded, but I cant open it with VLC (just import to Audacity with manual input of sample Rate, ByteOrder). Its because of RAW-data? how can able to save my recording like wav-file included sample-size, sampl-rate ...?
Audio.cpp
// ************************************************************************************************
// Audio-Class
// ************************************************************************************************
#include "Audio.h"
#include "Conf.h"
#include "Measure.h"
// ************************************************************************************************
Audio::Audio(Conf *conf)
{
m_conf = conf;
AudioRecord();
}
// ************************************************************************************************
//Initialization and signal-slot connection
void Audio::AudioRecord()
{
QAudioFormat format;
Conf values;
format.setSampleRate(values.getSampRate());
format.setChannelCount(values.getChannel());
format.setSampleSize(values.getSampSize());
format.setCodec(values.getCodec());
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!info.isFormatSupported(format))
{
qWarning() << "Default format not supported";
format = info.nearestFormat(format);
}
m_audio = new QAudioInput(format, this);
connect(m_audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
}
// ************************************************************************************************
//Start recording method
void Audio::startrecording(QString rec_file_path)
{
m_file.setFileName(rec_file_path);
m_file.open(QIODevice::WriteOnly);
m_audio->start(&m_file);
}
// ************************************************************************************************
//Stop recording
void Audio::stoprecording()
{
m_audio->stop();
m_file.close();
}
// ************************************************************************************************
//Recording DEBUG output
void Audio::handleStateChanged(QAudio::State newState)
{
switch (newState)
{
case QAudio::StoppedState:
if (m_audio->error() != QAudio::NoError)
{
qDebug() << "Error!!";
} else
{
qDebug() << "Finished recording";
}
break;
case QAudio::ActiveState:
qDebug() << "Started recording";
break;
default:
break;
}
}
// ************************************************************************************************
Audio.h
// ************************************************************************************************
// Audio-HEADER-file
// ************************************************************************************************
#ifndef AUDIO_H
#define AUDIO_H
// ************************************************************************************************
// Includes
#include <QDebug>
#include <QObject>
#include "Conf.h"
#include <QAudioInput>
#include <QDateTime>
#include <QTimer>
// ************************************************************************************************
// Define
#define SAVE_AUDIO_PATH "/home/nikitajarocky/workspace/QT/UART_PC/IO/"
// ************************************************************************************************
// Class variables and methods
class Audio : public QObject
{
Q_OBJECT
public:
explicit Audio(Conf *conf);
void start(QString file_name);
void stop();
void startrecording(QString);
void stoprecording();
signals:
public slots:
void handleStateChanged(QAudio::State);
void AudioRecord();
private:
Conf *m_conf;
Conf *m_samp_rate;
QAudioInput *m_audio;
QFile m_file;
};
// ************************************************************************************************
#endif // AUDIO_H
A much simpler approach is use QAudioRecorder, it handles the writing of the header and also handles the audio capture.
It saves you from big changes, if your goal is only recording.
See the example:
audio.h:
#ifndef AUDIO_H
#define AUDIO_H
#include <QtCore>
#include <QtMultimedia>
class Audio : public QObject
{
Q_OBJECT
public:
explicit Audio(QObject *parent = nullptr);
~Audio();
public slots:
QStringList audioInputs();
bool record(const QString &path, const QString &audio_input = QString());
void stop();
private:
QAudioRecorder *m_recorder;
};
#endif // AUDIO_H
audio.cpp:
#include "audio.h"
Audio::Audio(QObject *parent) : QObject(parent)
{
m_recorder = new QAudioRecorder(this);
}
Audio::~Audio()
{
stop();
}
QStringList Audio::audioInputs()
{
return m_recorder->audioInputs();
}
bool Audio::record(const QString &path, const QString &audio_input)
{
QAudioEncoderSettings audio_settings;
audio_settings.setCodec("audio/pcm");
audio_settings.setChannelCount(1);
audio_settings.setSampleRate(44100);
m_recorder->setEncodingSettings(audio_settings);
m_recorder->setOutputLocation(path);
m_recorder->setAudioInput(audio_input);
m_recorder->record();
if (m_recorder->state() == QAudioRecorder::RecordingState)
{
qDebug() << "Recording...";
return true;
}
else
{
qDebug() << qPrintable(m_recorder->errorString());
return false;
}
}
void Audio::stop()
{
if (m_recorder->state() == QAudioRecorder::RecordingState)
{
m_recorder->stop();
qDebug() << "Recording stopped";
}
else
{
qDebug() << "Nothing to stop";
}
}
Usage example (recording 5 seconds):
#include <QtCore>
#include "audio.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Audio audio;
audio.record("file.wav");
QTimer::singleShot(5 * 1000, &audio, &Audio::stop);
return a.exec();
}
I'm trying to make client and server using QTcpSocket and QTcpServer.
So, what happens to server.
I run the server, it starts listening (successfully [checked by myself])
I run client, enter 127.0.0.1 for IP address and 30000 for port
Client says that connection estabilished
Server doesn't do anything, just keep waiting
Parts of my program:
//server-work.h
#ifndef SERVERWORK_H
#define SERVERWORK_H
#include <QtCore>
#include <QSqlError>
#include <QDebug>
#include <QSqlQuery>
#include <unistd.h>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtSql/QSqlDatabase>
#include "lssclient.h"
class LSSClient;
class LTcpServer : public QTcpServer
{
Q_OBJECT
public:
class LTWorkWithClients : public QThread
{
//Q_OBJECT
public:
LTcpServer* server;
LTWorkWithClients(QObject* parent = 0, LTcpServer *server = 0):
QThread(parent)
{
this->server = server;
}
protected:
void run() {
qDebug() << "started";
server->workWithIncomingConnection();
}
};
QSqlDatabase db; // clients in database
LTWorkWithClients* t_workWithClients;
QQueue<quintptr> clientsToBeAttached;
QList<LSSClient*> clients;
LResult workWithIncomingConnection ();
LResult serverInit ();
LResult createDatabase ();
static QTextStream& qStdout ();
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
protected:
private:
};
#endif // SERVERWORK_H
I know that this nested thread class is strongly wrong way to do this thing, but i don't have much time to do it correctly
// server-work.cpp [PART]
LResult LTcpServer::serverInit()
{
checkError;
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("serverDB");
if (!db.open()) {
qDebug() << "Error opening database...";
qDebug() << db.lastError().text();
return LVError;
} else {
qDebug() << "Database successfully opened";
}
if(!this->listen(QHostAddress::Any, 30000)){
qDebug() << "Error starting listening...";
return LVError;
} else {
qDebug() << "Start listening successfully";
}
t_workWithClients = new LTWorkWithClients(this, this);
t_workWithClients->start();
return LVSuccess;
}
void LTcpServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << Q_FUNC_INFO << " new connection";
clientsToBeAttached.enqueue(socketDescriptor);
qDebug() << "here1";
}
LResult LTcpServer::workWithIncomingConnection()
{
bool toExit = false;
while (!toExit) {
checkError;
qDebug() << "1";
if (clientsToBeAttached.length() != 0) {
quintptr eachClientDescriptor = clientsToBeAttached.dequeue();
qDebug() << "2";
LSSClient* client = new LSSClient(this);
client->server = this;
client->socket->setSocketDescriptor(eachClientDescriptor);
qDebug() << "3";
client->registered = false;
client->server = this;
qDebug() << client->socket->localAddress();
connect(client->socket, SIGNAL(readyRead()), client, SLOT(onSokReadyRead()));
connect(client->socket, SIGNAL(connected()), client, SLOT(onSokConnected()));
connect(client->socket, SIGNAL(disconnected()), client, SLOT(onSokDisconnected()));
connect(client->socket, SIGNAL(error(QAbstractSocket::SocketError)),client, SLOT(onSokDisplayError(QAbstractSocket::SocketError)));
clients.append(client);
}
usleep(1000000);
}
return LVSuccess;
}
So, server just keep writing 1 (nothing more) every second, but client says that it is connected to the server.
This structure might help...
in your ltcpserver.h file:
class LTcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit LTcpServer(QObject * parent = 0);
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
private:
QThread *myThread;
};
and in your ltcpserver.cpp:
LTcpServer::LTcpServer(QObject * parent) : QTcpServer(parent)
{
if(this->listen(QHostAddress::Any,30000))
{
qDebug() << "server started...";
}
else
{
qDebug() << "server could not be started...";
}
myThread = new QThread();
myThread->start();
}
void LTcpServer::incomingConnection(qintptr socketDescriptor)
{
LSSClient * yourClient = new LSSClient(socketDescriptor);
yourClient->moveToThread(myThread);
clients->append(yourClient);
}
and in your lssclient.h
class LSSClient: public QObject
{
Q_OBJECT
public:
explicit LSSClient(qintptr socketDescriptor,QObject * parent = 0);
private:
void setupSocket(qintptr socketDescriptor);
QTcpSocket * socket;
public slots:
void readyRead();
void disconnected();
};
and in your lssclient.cpp
LSSClient::LSSClient(qintptr socketDescriptor,QObject * parent) : QObject(parent)
{
setupSocket(qintptr socketDescriptor);
}
void LSSClient::setupSocket(qintptr socketDescriptor)
{
socket = new QTcpSocket(this);
socket->setSocketDescriptor(sDescriptor);
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
}
void LSSClient::readyRead()
{
// do whatever you want here with incoming data
}
void LSSClient::disconnected()
{
// do what happens to client when disconnected
}
my problem is I need to show a message ask users wait when I check network availability of other clients.My way is I have a class workerThread to do the business, before start it I create a qMessageBox. But the message only shows the title, not the content. I have no idea why, pls help :(
Here's the worker thread:
#include <QObject>
#include <QString>
#include "clientdataobj.h"
class WorkerThread : public QObject
{
Q_OBJECT
public:
explicit WorkerThread(QObject *parent = 0);
QList<ClientDataObj> listClient() const;
void setListClient(const QList<ClientDataObj> &listClient);
signals:
void finished();
void error(QString err);
void listClientPingChecked( QList <ClientDataObj> list);
public slots:
void testPing();
private:
QList <ClientDataObj> mListClient;
bool pingEachClient(QString ip);
};
implement:
#include "workerthread.h"
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
WorkerThread::WorkerThread(QObject *parent) :
QObject(parent)
{
}
void WorkerThread::testPing()
{
if (mListClient.size()==0) {
emit finished();
return;
}
else{
for(unsigned i=0;i<mListClient.size();i++){
bool result = pingEachClient(mListClient[i].ip());
if(result)
mListClient[i].setStatus(true);
else
mListClient[i].setStatus(false);
}
emit listClientPingChecked(mListClient);
}
emit finished();
}
bool WorkerThread::pingEachClient(QString ip)
{
QString pingCommand = "ping " +ip + " -c 3 | grep loss | awk ' {print $7}' > pingResult.txt";
system(qPrintable(pingCommand));
QString lossPercentTxt = readFileText("pingResult.txt") ;
lossPercentTxt.chop(1);
int lossPercent = lossPercentTxt.toInt();
if(lossPercent<10){
return true;
}
else return false;
}
QList<ClientDataObj> WorkerThread::listClient() const
{
return mListClient;
}
void WorkerThread::setListClient(const QList<ClientDataObj> &listClient)
{
mListClient = listClient;
}
How I call it in MainWindow:
on_pbSendUpdate_clicked()
{
changeModeWaitPing();
getClientOnlineList();
}
getClientOnlineList()
{
if(mListClient.size()==0){
return;
}
mpThreadPing = new QThread;
mpWorkerThread = new WorkerThread;
mpWorkerThread->setListClient(mListClient);
connectThreadPingToGui();
mpThreadPing->start();
}
changeModeWaitPing()
{
ui->pbSendUpdate->setEnabled(false);
callMsgBox("Pinging client... Pls wait!");
// callWaitDialog();
}
callMsgBox( QString text)
{
if (NULL==mMsg) {
return;
}
mMsg->setWindowTitle("INFO");
// mMsg->setAttribute(Qt::WA_DeleteOnClose);
mMsg->setWindowModality(Qt::NonModal);
mMsg->setModal(false);
QString info ="Pinging client... Pls wait!";
mMsg->setText(info);
mMsg->show();
}
connectThreadPingToGui()
{
connect(mpWorkerThread, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(mpThreadPing, SIGNAL(started()), mpWorkerThread, SLOT(testPing()));
connect(mpWorkerThread, SIGNAL(finished()), mpThreadPing, SLOT(quit()));
connect(mpWorkerThread, SIGNAL(finished()), mpWorkerThread, SLOT(deleteLater()));
connect(mpThreadPing, SIGNAL(finished()), mpThreadPing, SLOT(deleteLater()));
connect(mpWorkerThread,SIGNAL(listClientPingChecked(QList<ClientDataObj>)),this,SLOT(updateListClientOnline(QList<ClientDataObj>)));
}
updateListClientOnline(QList<ClientDataObj> list)
{
mListClientOnline = list;
mPingDone = true;
if (NULL==mMsg) {
return;
}
else{
mMsg->hide();
}
if(mpDialogWaitPing==NULL){
return;
}
else{
mpDialogWaitPing->hide();
}
launchClientListTable();
}
You create a new thread, but you don't move any objects to that thread. So your new thread does nothing. I assume you wan't mpWorkerThread to be moved to the new thread. In that case you're missing mpWorkerThread->moveToThread(mpThreadPing);
I'm trying to do a simple GET request (with modified User-Agent), return response to QML and do a JSON parsing.
Actually it only returns page content when loading is complete but it doesn't return it to QML.
Sorry for the noob question. I'm new to this language and I'm trying to learn it :)
Here's my code:
Home.qml
function getRequest() {
[...]
console.log('Request...')
var jsonResult = JSON.parse(connectNet.connectUrl("http://myURL.com/index.php").toString())
lbOutput.text = jsonResult.predictions[0].description.toString()
}
}
connectnet.cpp
#include "connectnet.h"
#include "stdio.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
connectNet::connectNet(QObject *parent) : QObject(parent)
{
}
void connectNet::connectUrl(QString url)
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
QNetworkRequest request;
QNetworkReply *reply = NULL;
request.setUrl(QUrl(url));
request.setRawHeader( "User-Agent" , "FAKE USER AGENT HERE" );
reply = manager->get(request);
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(replyFinished(QNetworkReply*)));
}
QString connectNet::replyFinished(QNetworkReply *reply)
{
return reply->readAll();
}
appname.cpp
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <sailfishapp.h>
#include "connectnet.h"
int main(int argc, char *argv[])
{
//INIT SETTINGS
QGuiApplication *app = SailfishApp::application(argc, argv);
QQuickView *view = SailfishApp::createView();
connectNet ConnectNet;
view->rootContext()->setContextProperty("connectNet", &ConnectNet);
view->setSource(SailfishApp::pathTo("qml/APPNAME.qml"));
view->showFullScreen();
app->exec();
}
Hope I've well explained what I'm looking for. Thanks for your help.
====================================================
EDIT 20/08/2015: added updated connectnet.h
#ifndef CONNECTNET_H
#define CONNECTNET_H
#include <QObject>
#include <QNetworkReply>
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
class ConnectNet : public QObject
{
Q_OBJECT
QNetworkAccessManager m_manager;
public:
ConnectNet(QObject * parent = 0) : QObject(parent) {
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
}
signals:
void replyAvailable(const QString & reply);
public slots:
void sendRequest(const QString url) {
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "MyLittleAgent");
m_manager.get(request);
}
};
#endif // CONNECTNET_H
this part of code gives a lot of errors :( (screenshot below)
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
compiling erros: http://i.stack.imgur.com/30vWn.jpg
Your problem is that you think synchronously. The connectUrl cannot return a value (and it doesn't), since when it runs the result is not available. What you must do, instead, is for the ConnectNet class to emit a signal when the data is available.
It'd be a horrible idea if you tried to make a synchronous wrapper that did return the value: the QML engine would be stuck as long as it took for the result to be received. You could freeze your application by pulling the network cable at the right moment, or if the server was down. Users hate that, and it's a horrible antipattern that must be expediently eliminated and discouraged.
Here's how your ConnectNet (please, not connectNet, lowercase names are for members!) class could look. Note that the QNetworkAccessManager instance doesn't need to be a pointer.
class ConnectNet : public QObject {
Q_OBJECT
QNetworkAccessManager m_manager;
public:
ConnectNet(QObject * parent = 0) : QObject(parent) {
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
}
Q_SLOT void sendRequest(const QString & url) {
auto request = QNetworkRequest(QUrl(url));
request.setRawHeader("User-Agent", "MyLittleAgent");
m_manager.get(request);
}
Q_SIGNAL void replyAvailable(const QString & reply);
};
Since connectNet instance instance is exposed as a property in the global QML context, you can connect to its signals as follows:
function getRequest() {
connectNet.sendRequest("http://myURL.com/index.php")
}
function resultHandler(result) {
var jsonResult = JSON.parse(result.toString())
lbOutput.text = jsonResult.predictions[0].description.toString()
}
Rectangle { // or any other item
Component.onCompleted: {
connectNet.replyAvailable.connect(resultHandler)
}
...
}