Qt QNetworkAccessManager & multiple QNetworkReplay - qt

I have two http get methods.
First is getting UserID and second is getting full information about current user;
I want to handle finished signlas with different slots
handle GetUserID finished with GetUserIDCompleted and handle GetUserDetails with GetUserDetailsCompleted
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
nam = new QNetworkAccessManager(this);
GetUserID();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(GetUserIDCompleted(QNetworkReply*)));
GetUserDetails();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(GetUserDetailsCompleted(QNetworkReply*)));
}
does it possible to get QNetworkReplay in different SLOTS?

maybe you can do something like this: having an enum of the different methods
enum GetMethod
{
getUserId,
getUserDetails
};
And you keep a hash of the reply and the corresponding method:
QHash<QNetworkReply*, GetMethod> hash;
QNetworkReply *reply1 = nam->post(requestUserId, data);
hash[reply1] = GetMethod::getUserId;
QNetworkReply *reply2 = nam->post(requestUserDetails, data);
hash[reply2] = GetMethod::getUserDetails;
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
And have one slot that calls the right function
void MainWindow::finished(QNetworkReply *reply)
{
switch(hash[reply])
{
case GetMethod::getUserId:
GetUserIDCompleted(reply);
break;
case GetMethod::getUserDetails:
GetUserDetailsCompleted(reply);
break;
}
hash.remove(reply);
}
I haven't tried it and took some shortcuts but you get the spirit of it =) . It seems that you can retrieve the request with the answer, but I think it is easier with the enum.
Hope it helped

Every operation you do with your QNetworkAccessManager will return a QNetworkReply. This has also has an signal finished. Maybe you can connect this signal to your different slots.
Good luck

Related

How to add a QAction to a QListWidget

I have the following code:
roslaserscandoialog.h
public:
explicit ROSLaserScanDialog(QWidget *parent = nullptr);
~ROSLaserScanDialog();
QListWidgetItem *createItemFromAction(const QAction* action);
private slots:
void on_listWidget_itemClicked(QListWidgetItem *item);
private:
Ui::ROSLaserScanDialog *ui;
QAction *mAddMsgs;
QAction *mDeleteMsgs;
roslaserscandoialog.cpp
ROSLaserScanDialog::ROSLaserScanDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ROSLaserScanDialog)
{
ui->setupUi(this);
connect(ui->listWidget,SIGNAL(on_listWidget_itemClicked(QListWidgetItem*)),this,SLOT(createItemFromAction(QListWidgetItem*)));
}
QListWidgetItem *ROSLaserScanDialog::createItemFromAction(const QAction *action)
{
Q_ASSERT( action );
QListWidgetItem *mAddMsgs = new QListWidgetItem();
mAddMsgs->setText( action->text() );
mAddMsgs->setToolTip( action->toolTip() );
mAddMsgs->setIcon( action->icon() );
// ...
return mAddMsgs;
}
void ROSLaserScanDialog::on_listWidget_itemClicked(QListWidgetItem *item)
{
mAddMsgs = new QAction(QIcon(":ros.png"), tr("Add New Message"), this);
mDeleteMsgs = new QAction(QIcon(":remove_item.png"), tr("Remove Message"), this);
}
What I have done so far:
I came across this post and also this one. Very useful as I set up my project in a very similar way, but nothing happens when I try to click on the QListWidget.
I know that in order to trigger the action I have to go to the slot called itemClicked as I did on the above code provided.
On the official documentation I was trying to apply what is advised but I don't know why nothing happens.
Please point to the right direction for solving this problem.
Look at console output, there should a warning about connect failing. If you look at your code, the reason should be pretty obvious. Consider
SLOT(createItemFromAction(QListWidgetItem*))
versus your method which isn't even a slot
QListWidgetItem *createItemFromAction(const QAction* action);
See the difference?
And then you have this slot:
void on_listWidget_itemClicked(QListWidgetItem *item);
which you are trying to use as a signal
SIGNAL(on_listWidget_itemClicked(QListWidgetItem*))
That obviously won't work.
It's a bit unclear what you want to happen when an item is clicked, but maybe you just should call createItemFromAction directly from the on_listWidget_itemClicked.
Additionally, add debug print or use breakpoint to verify that the on_listWidget_itemClicked is actually called when you click an item. If not, then you are missing connecting the relevant signal from your list view, ie. ui->setupUi(this); does not have that connect (in other words you did not do the connection in the GUI Designer).

Display not updating on the QTimer?

Trying to display text based on when the QTimer fires off...
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_label1 = new QLabel("My Label not working", this);
QTimer* timerDisplay = new QTimer(this);
connect(timerDisplay, SIGNAL(Started()), this, SLOT(updateDisplay(this)));
timerDisplay->start(10);
}
void updateDisplay(MainWindow* m_this)
{
QString out;
out = "hello";
m_this->m_label1->setText("asdf");
}
connect(timerDisplay, SIGNAL(Started()), this, SLOT(updateDisplay(this)));
This statement is failing. And you're ignoring the message that Qt is printing on your console.
The problem is, you can't pass variables in connect statements like that. And what for, by the way? You can use this in the updateDisplay method without the need of passing it in explicitely!

Qt QNetworkRequest hang, but I believe I'm in an event loop

I'm running Qt 4.8.1
I'm trying to use QNetworkRequest to send a request and I'm getting a 'QEventLoop: Cannot be used without QApplication' error. I believe I'm running within an event loop.
void WebLoader::load()
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.bbc.co.uk/"));
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(checkForUpdateFinished(QNetworkReply*)));
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(checkForUpdateSlot()));
}
The manager->get(reply) call never returns.
This function is being called when a menu item is clicked upon. There is QWidget::event(QEvent) in its stack trace. The application is definitely running with the rest of a complex UI working.
as variations I've tried:
using new QNetworkAccessManager(mainWindow) - mainWindow inherits from QMainWindow
using new QNetworkAccessManager(application) - application inherits from QApplication
calling load() from a customEvent
calling load() from a timer callback
[edit]
I'm now constructing the QNetworkAccessManager in the MainWindow constructor:
MainWindow::MainWindow() : queryAnalyser(NULL)
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(managerFinished(QNetworkReply*)));
managerFinished is not being called.
I'm getting the debug IO:
'QObject: Cannot create children for a parent that is in a different thread.
(Parent is MainWindow(0x28fcd0), parent's thread is QThread(0x4862828), current thread is QThread(0x7d90b70)'
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
WXApplication *a = WXApplication::getApp();
MainWindow mainWin;
mainWin.show();
mainWin.checkArgs();
return app.exec();
}
Ensure that your QNetworkAccessManager is not destroyed at the end of the method which sens the request. If it is destroyed, your request is lost since the destroyed QNetworkAccessManager will not be able to send the finished() signal to the connected slot.
This is exactly what happened in the WebLoader::load(); method. The manager variable only exists during the method execution and the method will end before you will receive the reply.
What you can do is putting the QNetworkAccessManager in a global variable and use this global variable every time you need it :
Afile.hpp :
//...
#include <QNetworkAccessManager>
extern QNetworkAccessManager QNAM;
//...
Afile.cpp :
//...
#include "afile.hpp"
QNetworkAccessManager QNAM = QNetworkAccessManager();
//...
In your code (WebLoader::load(); for example) :
//...
#include "afile.hpp"
//...
QNetworkAccessManager * manager = &QNAM;
//...
In requests, set an originating object to "tag" requests and to ensure that the right methods will treat the right replies :
void WebLoader::load()
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.bbc.co.uk/"));
request.setOriginatingObject(this);
QNetworkAccessManager * manager = &QNAM;
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(checkForUpdateFinished(QNetworkReply*)));
manager->get(request);
}
void WebLoader::checkForUpdateFinished(QNetworkReply* reply)
{
if (reply == 0 || reply->request().originatingObject() != this)
{
return;
}
disconnect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(checkForUpdateFinished(QNetworkReply*)));
// Reply treatment
reply->deleteLater();
// ...
}
In your MainWindow constructor, forget the this if it is not necessary or use the QNAM global variable.

QErrorMessage and QValidator

I'm a student programmer and I'm trying to use some of the widgets provided in Qt to control my user input. I want the error message to display exactly whats wrong with the user input so I thought that using a switch statement would be best. I may not be correct about this and if there is a better way of doing this I am all ears! My main project will get allot of user input and it feels like there should be an easier way. The Qt Documentation lead me to believe that QValidator is at heart an enumerator data type. So I though I could use it in the switch statement however it doesn't seem to come up as an int. I'm not sure how to bring in an int value to make this work without defeating the intended convenience of the QValidator.
Any info on how to make this work or do it better would be greatly appreciated. Thanks in advance.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QValidator>
#include <QErrorMessage>
#include <QString>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButtonValidate, SIGNAL(clicked()), this, SLOT(checkData()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::checkData()
{
QValidator *doubleValidator = new QDoubleValidator();
switch(ui->lineEditValidate->setValidator(doubleValidator))
{
case 0:
QErrorMessage *error0 = new QErrorMessage(this);
error0->showMessage("The input is invalid");
break;
case 1:
QErrorMessage *error1 = new QErrorMessage(this);
error1->showMessage("The input is incomplete");
break;
case 2:
break;
default:
QErrorMessage *error = new QErrorMessage(this);
error->showMessage("No input");
}
}
In this line of code
switch(ui->lineEditValidate->setValidator(doubleValidator))
you're attempting to switch on the return value of the setValidator() function call, which returns void.
From what I gather, it looks like you want to do something along these lines:
In the constructor:
ui->setupUi(this);
connect(ui->pushButtonValidate, SIGNAL(clicked()), this, SLOT(checkData()));
QValidator *doubleValidator = new QDoubleValidator();
ui->lineEditValidate->setValidator(doubleValidator);
and in checkData()
int pos = 0;
switch(ui->lineEditValidate->validator()->validate(ui->lineEditValidate->text(), pos))
{
case QValidator::Invalid:
...
case QValidator::Incomplete:
...
case QValidator::Invalid:
...
}

How can I solve the problem of (Incompatible sender/receiver arguments)?

Here is the code where I use CONNECT.I use it to go to the slot slotReadyRead where i can read the content the reply.
But I have a message while debugging or running the program which is
QObject::connect: Incompatible sender/receiver arguments
QNetworkReplyImpl::readyRead() --> MainWindow::slotReadyRead(QNetworkReply*)
.cpp
void MainWindow::on_pushButton_clicked()
{
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setUrl(QUrl("http://lascivio.co/mobile/get.php?name=marwa"));
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead(QNetworkReply*)));
}
void MainWindow::slotReadyRead(QNetworkReply* reply)
{
QByteArray b (reply->readAll());
QString s(b);
ui->lineEdit->setText(s);
}
.h
public slots:
void slotReadyRead(QNetworkReply* reply);
The slot needs to have a signature compatible with the signal. So either define it as:
void slotReadyRead();
Or make the reply optional:
void slotReadyRead(QNetworkReply* reply = null);
You cannot force a plug into a socket, if it is not meant to be. I see two options:
Make reply a member of MainWindow (the quick and dirty solution)
Create a new class that will have a QNetworkReply* as a member and a slot to process the data of the reply, when it is ready.
BTW: I think you want to connect(reply, SIGNAL(finished()), this, SLOT(slotProcessReply()) (documentation). And here is the HTTP example from the Qt example collection! Have a look at network/http/httpwindow.h and network/http/httpwindow.cpp

Resources