I've been having this problem for few weeks, still didn't found a solution anywhere. I did everything I could to find the problem, everything looks good but for some reason it doesn't work.
I tested the connection, between the loginFailed() signal, and handleLoginFailed() slot, it returned True, printed the object info, it shows the connections. Tried different Qt::connectionTypes, nothing works.
The two objects are defined bellow.
LoginService.h
#ifndef LOGINSERVICE_H
#define LOGINSERVICE_H
#include <QObject>
#include <QVariant>
#include "libs/qubeapi/QubeAPI.h"
#include "libs/qubeapi/LoginCommand.h"
#include "libs/qubeapi/APIBridge.h"
#include "libs/mge-users/User.h"
#include "libs/mge-users/permissionfactory.h"
#include "Utils/serverstate.h"
#include "Utils/singleton.h"
#include "Utils/baseservice.h"
class LoginService : public QObject
{
Q_OBJECT
QubeAPI* api;
APIBridge* bridge;
LoginCommand* loginCmd;
QString m_userType;
QString m_firstName;
QString m_lastName;
User *m_user;
public:
explicit LoginService(QObject *parent = nullptr);
Q_PROPERTY(QString userType READ userType WRITE setUserType NOTIFY userTypeChanged)
Q_PROPERTY(QString firstName READ firstName WRITE setFirstName NOTIFY firstNameChanged)
Q_PROPERTY(QString lastName READ lastName WRITE setLastName NOTIFY lastNameChanged)
Q_PROPERTY(User* user READ user WRITE setUser NOTIFY userChanged)
const QString &userType() const;
void setUserType(const QString &newUserType);
const QString &firstName() const;
void setFirstName(const QString &newFirstName);
const QString &lastName() const;
void setLastName(const QString &newLastName);
User *user() const;
void setUser(User *newUser);
signals:
void success(QString token);
void loginFailed();
void userTypeChanged();
void firstNameChanged();
void lastNameChanged();
void staffLogout();
void userTypeRecived();
void userChanged();
public slots:
void requestLogin(QString userName, QString password);
void loginResponse(QString jsonData);
void doClose();
void prepareGetUserType();
void loadUserType(QString jsonData);
};
#endif // LOGINCONTROLLER_H
The function that emits the signal:
void LoginService::loginResponse(QString jsonData)
{
QSignalSpy spy(this,SIGNAL(loginFailed()));
if(jsonData == "") {
emit Singleton<ServerState>::GetInstance().offlineServer();
return;
}
QJsonDocument doc = QJsonDocument::fromJson(jsonData.toUtf8());
QString token = doc["data"]["tokenAuth"]["token"].toString();
if(!token.isEmpty()) {
UserSession::getInstance()->setAuthToken(token);
emit success(token);
prepareGetUserType();
} else {
qDebug() << "Urmeaza eroare";
QString errorMsg = doc["errors"][0]["message"].toString();
emit loginFailed();
qDebug() << spy.count();
}
}
The controller class that has the slot:
#ifndef LOGINCONTROLLER_H
#define LOGINCONTROLLER_H
#include <Utils/basecontroller.h>
#include <Utils/enginefactory.h>
#include <Utils/singleton.h>
#include <QQuickWindow>
#include <QQuickItem>
#include <QThread>
#include <QProperty>
#include <QQmlProperty>
#include "loginservice.h"
#include "draggableviewhelper.h"
#include <QMouseEvent>
class LoginController : public BaseController
{
Q_OBJECT
private:
QQuickWindow* window;
QQuickItem* login;
QQuickItem* userTextField;
QQuickItem* passwordTextField;
DraggableViewHelper* draggableViewHelper;
QQuickItem* mouseArea;
LoginService* service;
QPointF lastMousePosition;
public:
explicit LoginController(QObject *parent = nullptr);
// BaseController interface
void initialize();
// void setService(BaseService* s);
void setService(LoginService* s);
void setLastMousePosition(QPointF lastMousePosition);
public slots:
void handleLoginResponseSuccess(QString loginResponse);
void handleLoginResponseFailed();
void handlePositionChanged();
void handleLogout();
};
#endif // LOGINCONTROLLER_H
The initializer methods
void LoginController::initialize()
{
this->engine = Singleton<EngineFactory*>::GetInstance()->createEngine("qrc:/qml/LoginWindow.qml");
this->window = qobject_cast<QQuickWindow*>(this->engine->rootObjects().first());
// Create a draggable view helper, use window as input
// Get the view from the engine
this->draggableViewHelper = new DraggableViewHelper(this->window);
this->window->setFlags(Qt::Window | Qt::FramelessWindowHint);
this->login = window->findChild<QQuickItem*>("login");
this->userTextField = QQmlProperty::read(this->login,"user").value<QQuickItem*>();
this->passwordTextField = QQmlProperty::read(this->login,"password").value<QQuickItem*>();
// Set the mouseArea with the mainMouseArea item of the window
this->mouseArea = window->findChild<QQuickItem*>("mainMouseArea");
// Connect onClicked from mouse area, to handleMove of this
QObject::connect(this->mouseArea,SIGNAL(positionMoved()),this,SLOT(handlePositionChanged()));
}
void LoginController::setService(LoginService *s)
{
this->service = s;//new LoginService;
connect(this->service,SIGNAL(loginFailed()),this,SLOT(handleLoginResponseFailed()));
connect(this->service,SIGNAL(success(QString)),this,SLOT(handleLoginResponseSuccess(QString)));
connect(login,SIGNAL(doLogin(QString,QString)),this->service,SLOT(requestLogin(QString,QString)));
this->dumpObjectInfo();
this->service->dumpObjectInfo();
}
The slot
void LoginController::handleLoginResponseFailed()
{
qDebug() << "Failed";
QQmlProperty::write(this->userTextField,"state",QVariant::fromValue(QString{"default-error"}));
QQmlProperty::write(this->passwordTextField,"state",QVariant::fromValue(QString{"password-error"}));
}
This is the main.cpp file, where the objects are created
QApplication app1(argc, argv);
LoginController* loginCtrl = new LoginController;
LoginService* loginService = new LoginService;
QObject::connect(loginService, &LoginService::userTypeRecived,[&](){
qDebug() << "Failed to login";
});
qDebug() << loginService;
loginCtrl->initialize();
loginCtrl->setService(loginService);
//This will trigger the signal
// loginService->loginResponse("{\"errors\":[{\"message\":\"Please enter valid credentials\",\"locations\":[{\"line\":1,\"column\":12}],\"path\":[\"tokenAuth\"]}],\"data\":{\"tokenAuth\":null}}");
return app1.exec();
Related
I'm trying to create a simple login app, which will authenticate via Google Firebase. So far, I have the authentication code working fine.
Header file:
#ifndef AUTHHANDLER_H
#define AUTHHANDLER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
class AuthHandler : public QObject
{
Q_OBJECT
public:
explicit AuthHandler(QObject *parent = nullptr);
~AuthHandler();
void setAPIKey(const QString & apiKey);
void signUserUp(const QString & emailAddress, const QString & password);
void signUserIn(const QString & emailAddress, const QString & password);
public slots:
void networkReplyReadyRead();
void performAuthenticatedDatabaseCall();
signals:
void userSignedIn();
private:
void performPOST( const QString & url, const QJsonDocument & payload);
void parseResponse( const QByteArray & response);
QString m_apiKey;
QNetworkAccessManager * m_networkAccessManager;
QNetworkReply * m_networkReply;
QString m_idToken;
};
#endif // AUTHHANDLER_H
Authentication .cpp file
#include "authhandler.h"
#include <QDebug>
#include <QVariantMap>
#include <QNetworkRequest>
#include <QJsonObject>
AuthHandler::AuthHandler(QObject *parent)
: QObject{parent}
, m_apiKey( QString() )
{
m_networkAccessManager = new QNetworkAccessManager( this );
connect( this, &AuthHandler::userSignedIn, this, &AuthHandler::performAuthenticatedDatabaseCall );
}
AuthHandler::~AuthHandler()
{
m_networkAccessManager->deleteLater();
}
void AuthHandler::setAPIKey(const QString &apiKey)
{
m_apiKey = apiKey;
}
void AuthHandler::signUserUp(const QString &emailAddress, const QString &password)
{
QString signUpEndpoint = "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + m_apiKey;
QVariantMap variantPayload;
variantPayload["email"] = emailAddress;
variantPayload["password"] = password;
variantPayload["returnSecureToken"] = true;
QJsonDocument jsonPayload = QJsonDocument::fromVariant( variantPayload );
performPOST( signUpEndpoint, jsonPayload);
}
void AuthHandler::signUserIn(const QString &emailAddress, const QString &password)
{
QString signInEndpoint = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + m_apiKey;
QVariantMap variantPayload;
variantPayload["email"] = emailAddress;
variantPayload["password"] = password;
variantPayload["returnSecureToken"] = true;
QJsonDocument jsonPayload = QJsonDocument::fromVariant( variantPayload );
performPOST( signInEndpoint, jsonPayload);
}
main.cpp file
#include <QCoreApplication>
#include "authhandler.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
//QCoreApplication a(argc, argv);
// AuthHandler authHandler;
//authHandler.setAPIKey("AIzaSyB-nAN8OlgxHzXC5gpISkodjEZJ7IdSpgI");
// authHandler.signUserIn("user2#user.com", "password123!");
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
AuthHandler authHandler;
authHandler.setAPIKey("AIzaSyB-nAN8OlgxHzXC5gpISkodjEZJ7IdSpgI");
authHandler.signUserIn("user3#user.com", "password123!");
return app.exec();
}
As you can see, I'm currently hardcoding the values used in the SignUserIn function. These values are then updated in Firebase, and this is working. My question is, how do I make it so that the hard-coded values are input by an user in a qml file? I created a qml file with the required layout, but I'm having trouble setting it up so that the .cpp file function executes when a button is clicked in qml.
Make the method signUserIn a slot in the AuthHandler class
public slots:
void signUserIn(const QString & emailAddress, const QString & password);
Register your AuthHandler to the QML engine in main.cpp
qmlRegisterSingletonInstance("AuthHandler", 1, 0, "AuthHandler", &authHandler);
Import the AuthHandler in QML
import AuthHandler
Send the user credentials from QML to your handler
TextEdit {
id: user
text: "user"
}
TextEdit {
id: password
text: "password"
}
Button {
text: qsTr("Login");
onClicked: {
console.log("login: " + user.text + " password: " + password.text);
AuthHandler.signUserIn(user.text, password.text);
}
}
I'm working on car sharing project. So, I've done login and registration, after login the main menu is opening. In main menu I need to output a balance of an account. I do like this:
mainwindow.h
#include <QMainWindow>
#include <QMessageBox>
#include <string>
#include <QDebug>
#include "mainmenu.h"
using namespace std;
class RegData;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
RegData& givedata(); // the object of class from which I will get balance and output it in main menu
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_button_reg_clicked();
void on_button_log_clicked();
private:
Ui::MainWindow *ui;
Mainmenu *second; // the error is in this line
};
class RegData
{
private:
QString login;
QString email;
QString password;
int balance;
public:
RegData(QString log = "", QString mail = "", QString pass = "", int bal=0) : login(log), email(mail), password(pass), balance(bal)
{
}
void output()
{
qDebug() << login<<email<<password<<balance;
}
QString getLogin()
{
return login;
}
QString getEmail()
{
return email;
}
QString getPassword()
{
return password;
}
int getBalance()
{
return balance;
}
void setLogin(QString log)
{
login = log;
}
void setEmail(QString mail)
{
email = mail;
}
void setPassword(QString pass)
{
password = pass;
}
void setBalance(int balanc)
{
balance = balanc;
}
};
Ok, how I did registration:
Receiving data from file into QVector data;
Receiving data from login/pass lines etc.
If login hasn't registered yet, put the data into file
So, there are a part of code in login system. The part checks is account registered, if it is, do something. In my case I change 'givedata()' values
for(QVector<RegData>::iterator it = data.begin(); it<data.end(); it++)
{
if(loginline == it->getLogin() && passwordline == it->getPassword() || loginline == it->getEmail() && passwordline == it->getPassword())
{
islog = true;
givedata().setLogin(loginline);
givedata().setEmail(it->getEmail());
givedata().setPassword(passwordline);
givedata().setBalance(it->getBalance());
break;
}
else
{
islog = false;
}
}
but I have an error
C:\Users\david\Documents\Carsharring_files\mainwindow.h:33: ошибка: 'Mainmenu' does not name a type
Mainmenu *second;
^
What is the line for? This is for main menu window object
I need to do some things with 'givedata()' in another window, there is why I do it
mainmenu.h is included
#ifndef MAINMENU_H
#define MAINMENU_H
#include <QDialog>
#include <QMessageBox>
#include "addmoney.h"
#include "mainwindow.h"
namespace Ui {
class Mainmenu;
}
class Mainmenu : public QDialog
{
Q_OBJECT
public:
explicit Mainmenu(QWidget *parent = 0);
~Mainmenu();
private slots:
void on_plus_clicked();
private:
Ui::Mainmenu *ui;
};
#endif // MAINMENU_H
I changed nothing in mainmenu.h, but includes
You have a cyclic dependency of header files.
mainmenu,h includes mainwindow.h
mainwindow.h includes mainmenu.h
That's trouble (and note that couldn't be determined without seeing both header files).
Here: Qt multi-thread with GUI I've learned how to create a background worker (the Engine class).
In that class, I have a QSerialPort object, that runs in the main thread (see How to setup QSerialPort on a separate thread?).
I'm using the signal/slot mechanism to send/receive data. But it works in one-way only. The signals emitted from the Engine object ("worker thread") are received by the QSerialPort ("main thread"). The viceversa doesn't work: any signal emitted from QSerialPort is not received by the Engine.
engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <QObject>
#include <QTimer>
#include "myserial.h"
class Engine : public QObject
{
Q_OBJECT
public:
explicit Engine(QObject *parent = 0);
private:
QTimer m_timer;
MySerial m_serial;
signals:
void serialSendMessage(QByteArray data);
private slots:
void lineReceived(QByteArray line);
void foo();
public slots:
void run();
void open(QString port, quint32 baudrate);
void close();
};
#endif // ENGINE_H
engine.c
#include "engine.h"
#include <QDebug>
Engine::Engine(QObject *parent) : QObject(parent)
{
connect(&m_timer, &QTimer::timeout, this, &Engine::foo);
m_timer.setInterval(200);
}
// THIS IS NEVER EXECUTED!
void Engine::lineReceived(QByteArray line)
{
qDebug() << line;
}
// THIS IS RECEIVED BY QSERIALPORT
void Engine::foo()
{
emit serialSendMessage("Hello World!");
}
void Engine::run()
{
// THIS DOESN'T WORK!
connect(&m_serial, &MySerial::lineReceived, this, &Engine::lineReceived);
// THIS WORK!
connect(this, &Engine::serialSendMessage, &m_serial, &MySerial::sendMessage);
}
void Engine::open(QString port, quint32 baudrate)
{
m_serial.open(port, baudrate);
QTimer::singleShot(0, &m_timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
}
void Engine::close()
{
m_serial.close();
}
MySerial.h
#ifndef MYSERIAL_H
#define MYSERIAL_H
#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
class MySerial : public QSerialPort {
Q_OBJECT
public:
explicit MySerial(QObject *parent = 0);
bool open(QString port, quint32 baudrate);
using QSerialPort::open;
QByteArray sendMessage(QByteArray data, bool nmea);
signals:
void lineReceived(QByteArray line);
private slots:
void onReadyRead();
};
#endif // MYSERIAL_H
MySerial.c
#include "myserial.h"
#include <QDebug>
MySerial::MySerial(QObject *parent) : QSerialPort(parent) {
}
bool MySerial::open(QString port, quint32 baudrate)
{
disconnect(this, 0, 0, 0);
connect(this, &FemtoSerial::readyRead, this, &MySerial::onReadyRead);
setPortName(port);
if (!open(QIODevice::ReadWrite)) return false;
setDataBits(QSerialPort::Data8);
setParity(QSerialPort::NoParity);
setStopBits(QSerialPort::OneStop);
setBaudRate(baudrate);
setFlowControl(QSerialPort::NoFlowControl);
return true;
}
void MySerial::onReadyRead() {
static QList<QByteArray> lines;
static QByteArray buffer;
buffer += readAll();
int index = buffer.indexOf("\r");
while (index != -1) {
lines.append(buffer.left(index + 1));
buffer = buffer.mid(index + 1);
index = buffer.indexOf("\r");
}
// THIS SIGNAL IS EMITTED!
while (!lines.isEmpty()) emit lineReceived(lines.takeFirst());
}
QByteArray MySerial::sendMessage(QByteArray data) {
write(data);
return data;
}
EDIT
Trying to add a QEventLoop:
void Engine::run()
{
QEventLoop loop;
connect(&m_serial, &MySerial::lineReceived, this, &Engine::lineReceived);
connect(this, &Engine::serialSendMessage, &m_serial, &MySerial::sendMessage);
loop.exec();
}
The behavior is the same: the data is sent, but the receiving slot is never executed.
bool MySerial::open(QString port, quint32 baudrate)
{
//<s>disconnect(this, 0, 0, 0);</s> // <--- strikeout
connect(this, &FemtoSerial::readyRead, this, &MySerial::onReadyRead);
// ...
}
From the documentation:
Disconnect everything connected to an object's signals
disconnect(myObject, 0, 0, 0);
it means from the signals of myObject not the other way round.
That line prevents the slot in Engine to be executed because it has just disconnected from the source signal.
Engine might disconnect when the port closes, to avoid multiple connections on the next opening.
I created a small server/client application, and for testing I put the server/client function into a separate application.
The main client functions are
Client::Client(QString purpose) : networkSession(0)
{
Client::purpose = purpose;
tcpSocket = new QTcpSocket;
Client::blockSize = 0;
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));
QNetworkConfigurationManager manager;
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
{
// Get saved network configuration
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
settings.endGroup();
// If the saved network configuration is not currently discovered use the system default
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
if ((config.state() & QNetworkConfiguration::Discovered) !=
QNetworkConfiguration::Discovered) {
config = manager.defaultConfiguration();
}
networkSession = new QNetworkSession(config, this);
connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));
}
qDebug() << "Client set up, waiting";
}
void Client::connectToServer(QString ipAddr, quint32 port)
{
qDebug() << "Connecting to Host on port " << port << ' ' << (quint16)port;
tcpSocket->connectToHost(ipAddr, port);
emit this->connectionResult((tcpSocket->state() == QAbstractSocket::UnconnectedState)?false:true);
if (tcpSocket->waitForConnected(1000))
qDebug("Connected!");
qDebug() << "Am I connected" << tcpSocket->state();
std::cout << "Am I not connected" << tcpSocket->state();
}
and the server-functions:
Server::Server(QString ipAddr, quint32 port, QString purpose)
: tcpServer(0), networkSession(0)
{
Server::clientConnection = NULL;
Server::purpose = purpose;
Server::port = port;
QNetworkConfigurationManager manager;
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
// Get saved network configuration
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
settings.endGroup();
// If the saved network configuration is not currently discovered use the system default
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
if ((config.state() & QNetworkConfiguration::Discovered) !=
QNetworkConfiguration::Discovered) {
config = manager.defaultConfiguration();
}
networkSession = new QNetworkSession(config, this);
connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));
//statusLabel->setText(tr("Opening network session."));
networkSession->open();
} else {
sessionOpened();
}
//connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(openNewConnection()));
//connect(tcpServer, &QTcpServer::newConnection, this, &Server::openNewConnection);
}
void Server::sessionOpened()
{
// Save the used configuration
if (networkSession) {
QNetworkConfiguration config = networkSession->configuration();
QString id;
if (config.type() == QNetworkConfiguration::UserChoice)
id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString();
else
id = config.identifier();
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id);
settings.endGroup();
}
tcpServer = new QTcpServer(this);
if (!tcpServer->listen(QHostAddress::Any, Server::port)) {
return;
}
qDebug() << "Server listening on: " << tcpServer->serverPort();
//! [0]
QString ipAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
// use the first non-localhost IPv4 address
for (int i = 0; i < ipAddressesList.size(); ++i) {
if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
ipAddressesList.at(i).toIPv4Address()) {
ipAddress = ipAddressesList.at(i).toString();
break;
}
}
// if we did not find one, use IPv4 localhost
if (ipAddress.isEmpty())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
//! [1]
}
void Server::openNewConnection(void)
{
qDebug() << "New conn incoming!";
Server::clientConnection = tcpServer->nextPendingConnection();
QVariant ipAddr_QVar(clientConnection->peerAddress().toString());
qDebug() << "Got new connection!";
emit gotNewConnection(ipAddr_QVar);
}
The main problem here is that even if I get a "Connected" from
if (tcpSocket->waitForConnected(1000))
qDebug("Connected!");
qDebug() << "Am I connected" << tcpSocket->state();
in the client function, but the server function openNewConnection() never gets called. Why? How can I find the bug?
If a minimal working example is necessary, I can provide the whole code, but here I just wanted to provide the most important functions.
Edit:
client.h:
#ifndef CLIENT_H
#define CLIENT_H
//#include <QDialog>
#include <iostream>
#include <QTcpSocket>
class QComboBox;
class QDialogButtonBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QTcpSocket;
class QNetworkSession;
class Client : public QObject
{
Q_OBJECT
private:
QTcpSocket *tcpSocket;
QString currentFortune;
quint16 blockSize;
QPair<QString, QPair<QString, QVariant> > data;
QNetworkSession *networkSession;
QString purpose;
signals:
void gotData(QPair<QString, QPair<QString, QVariant> >);
void noConnection(void);
void connectionResult(bool);
void isDisconnect(bool);
public slots:
void displayError(QAbstractSocket::SocketError socketError);
void sessionOpened();
void getInfo();
void readData();
void connectToServer(QString ipAddr, quint32 port);
void disconnectFromServer();
private:
public:
Client(QString purpose);
};
#endif // CLIENT_H
server.h:
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
#include <iostream>
//#include <QtTest/QTest>
#include <QSignalSpy>
#include <QTcpSocket>
#include <QDebug>
//#include <QMessageBox>
#include <QNetworkInterface>
#include <typeinfo>
#include <QStringList>
//#include <QSignalSpy>
QT_BEGIN_NAMESPACE
class QTcpServer;
class QNetworkSession;
QT_END_NAMESPACE
class Server : public QObject
{
Q_OBJECT
public slots:
void sessionOpened();
void sendFortune(void);
void sendData(QPair<QString, QPair<QString, QVariant> > data);
void sendFile(QVariant fileName);
void disconnectServer(void);
void openNewConnection(void);
signals:
void gotNewConnection(QVariant);
private:
QString purpose;
QTcpServer *tcpServer;
QString ipAddr;
quint32 port;
QTcpSocket *clientConnection;
quint32 BlockSize;
bool firstTime;
QSignalSpy * m_pSignalSpy;
QStringList fortunes;
QNetworkSession *networkSession;
//QNetworkConfiguration config;
public:
Server(QString ipAddr, quint32 port, QString purpose = "");
};
#endif // SERVER_H
The problem lies with your QNetworkSession, you have declared it in scope. Meaning once you leave that function the QNetworkSession gets destroyed. A destroyed object cannot emit a signal. Maybe make it a member variable or construct it in your header.
I have a C++ Qt program that uses QThreadPool to process files in no more than MAX_THREAD_COUNT threads. And I'm having troubles with Qt::QueuedConnection. It looks like signals got lost. But with Qt::DirectConnection it works pretty perfect.
I'd be thankful if someone will explain what's going on.
UPDATE: This code works well in Qt, but not in Visual Studio 2005. In VS it stops after the first thread finished (but works with Qt::DirectConnection)
That's how it looks:
Manager.h:
#ifndef MANAGER_H
#define MANAGER_H
#include <QObject>
#include <QThreadPool>
#include <QDebug>
#include "threadbody.h"
class Manager : public QObject
{
Q_OBJECT
private:
QList<QString> processedfiles;
QList<QString> resultfiles;
bool ok;
QString lasterror;
public slots:
void addToProcessedFiles(const QString& filename);
void addToResultFiles(const QString& filename);
void setErrorMessage(const QString& message);
void startNewThread();
public:
bool startManager(const QString& firstfile);
explicit Manager(QObject *parent = 0);
~Manager();
};
#endif // MANAGER_H
ThreadBody.h:
#ifndef THREADBODY_H
#define THREADBODY_H
#include <QTemporaryFile>
#include <QRunnable>
#include <QTextStream>
#define MAX_THREAD_COUNT 4
class ThreadBody : public QObject, public QRunnable
{
Q_OBJECT
private:
QString filename;
public:
ThreadBody(const QString& filename);
~ThreadBody();
void run();
signals:
void sendResult(const QString& filename);
void sendFileName(const QString& filename);
void taskDone();
void threadError(const QString& message);
};
#endif // THREADBODY_H
Manager.cpp:
Manager::Manager(QObject *parent) :
QObject(parent)
{
ok=true;
QThreadPool::globalInstance()->setMaxThreadCount(MAX_THREAD_COUNT);
}
void Manager::addToProcessedFiles(const QString& filename)
{
processedfiles.push_back(filename);
if(QThreadPool::globalInstance()->activeThreadCount()<MAX_THREAD_COUNT)
startNewThread();
}
void Manager::addToResultFiles(const QString& filename)
{
resultfiles.push_back(filename);
}
void Manager::setErrorMessage(const QString& message)
{
ok=false;
lasterror=message;
}
void Manager::startNewThread()
{
if(processedfiles.isEmpty())
return;
if(!ok)
return;
QString filename=processedfiles.takeFirst();
ThreadBody* task=new ThreadBody(filename);
connect(task,SIGNAL(taskDone()),this,SLOT(startNewThread()),Qt::QueuedConnection);
connect(task,SIGNAL(sendResult(const QString&)),this,SLOT(addToResultFiles(const QString&)),Qt::QueuedConnection);
connect(task,SIGNAL(sendFileName(const QString&)),this,SLOT(addToProcessedFiles(const QString&)),Qt::QueuedConnection);
connect(task,SIGNAL(threadError(const QString&)),this,SLOT(setErrorMessage(const QString&)),Qt::QueuedConnection);
qDebug()<<"thread starts";
QThreadPool::globalInstance()->start(task);
}
bool Manager::startManager(const QString& firstfile)
{
processedfiles.push_back(firstfile);
startNewThread();
QThreadPool::globalInstance()->waitForDone();
return ok;
}
Manager::~Manager(){}
ThreadBody.cpp:
#include "threadbody.h"
#include <QThreadPool>
ThreadBody::ThreadBody(const QString& filename)
{
this->filename=filename;
}
ThreadBody::~ThreadBody(){}
void ThreadBody::run()
{
QFile file(filename);
if(!file.open(QIODevice::ReadOnly))
{
QString message=QString("Thread can't open file=%1: %2").arg(filename).arg(file.errorString());
emit threadError(message);
emit taskDone();
return;
}
QTextStream in(&file);
QTemporaryFile newProcessedFile;
newProcessedFile.setAutoRemove(false);
if(!newProcessedFile.open())
{
QString message="Thread can't open temporary file";
emit threadError(message);
emit taskDone();
return;
}
QTextStream out(&newProcessedFile);
QTemporaryFile resultFile;
resultFile.setAutoRemove(false);
if(!resultFile.open())
{
QString message="Thread can't open temporary file";
emit threadError(message);
emit taskDone();
return;
}
QTextStream resultOut(&resultFile);
while(!in.atEnd())
{
//!---time consuming task---!//
//example//
QString currentLine=in.readLine();
out<<currentLine;
resultOut<<currentLine;
}
resultFile.close();
newProcessedFile.close();
file.remove();
emit sendResult(resultFile.fileName());
emit sendFileName(newProcessedFile.fileName());
emit taskDone();
}
main.cpp:
#include <QCoreApplication>
#include "manager.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Manager manager;
QString filename="C:/airtest/ask.cpp";
manager.startManager(filename);
return a.exec();
}