reply not declared in this scope - c++

Why this code doesn't work?
void MainWindow::on_startButton_clicked()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QNetworkReply *red = nam->get(QNetworkRequest(QUrl("someurl/to/file")));
QObject::connect(red, SIGNAL(readyRead()), this, SLOT(readingReadyBytes()));
QObject::connect(red, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64)));
}
void MainWindow::readingReadyBytes() {
QFile file("C:\\test.bin");
file.open(QIODevice::WriteOnly);
file.write(red->read(red->bytesAvailable()));
file.close();
}
QT throws error: 'red' was not declared in this scope
file.write(red->read(red->bytesAvailable()));
^

You should declare red as a class member not in void MainWindow::on_startButton_clicked function, Then you can assign a value to it in on_startButton_clicked functon, so:
Declare red as class member :
// in your MainWindow class
QNetworkReply *red;
Assign value to it in on_startButton_clicked method:
...
red = nam->get(QNetworkRequest(QUrl("someurl/to/file")));
...

because red is local to on_startButton_clicked().
If you are trying to download and save a file, your code will not work as you are creating the file and closing it every time readingReadyBytes() is called.
as suggested by ABFORCE you should declare red as member.
Then you should connect the event finished() of QNetworkReply to a slot that closes the file.

Related

Put arguments in slots in Qt

I've made a class named MyWindow which inherits from QWidget to create a window. Here is the content of mywindow.h:
class MyWindow: public QWidget{
public:
MyWindow(QString title,QString icon,int w = 600,int h = 400);
int getWidth() const;
int getHeight() const;
public slots:
void openDialogBox(QString title,QString message);
private:
int m_width;
int m_height;
};
There is a openDialogBox slot which takes the title and the message of the dialog box as arguments.
I've made a menu bar which basically looks like this:
MyWindow myWindow("Example window",QCoreApplication::applicationDirPath() + "/icon.png");
QMenuBar menuBar(&myWindow);
menuBar.setGeometry(0,0,myWindow.getWidth(),menuBar.geometry().height());
QMenu *fileMenu = new QMenu("&File");
QAction *fileMenu_open = fileMenu->addAction("&Open");
MyWindow::connect(fileMenu_open,&QAction::triggered,&myWindow,&MyWindow::openDialogBox);
In the last line, I would like to send arguments to the slot &MyWindow::openDialogBox. I tried to do:
MyWindow::connect(fileMenu_open,&QAction::triggered,&myWindow,&MyWindow::openDialogBox("Title","Hello, this is a message"));
but it didn't work (I don't need you to explain why it didn't work, I already know why). How to do this properly so that it works?
Since you are using the New Signal Slot Syntax, I would suggest using a c++11 lambda instead of a slot, and call the desired function inside your slot, here is how your connect call would look like:
QObject::connect(fileMenu_open, &QAction::triggered, &myWindow, [&myWindow](){
myWindow.openDialogBox("Title","Hello, this is a message");
});
Note that openDialogBox is not required to be a slot this way, it can be any normal function.
If your compiler does not support C++11 lambda expression, you might have to declare a slot that does not take any argument, and connect to that slot. And inside that slot call your function with the desired arguments. . .
Use lambdas
QObject::connect(fileMenu_open, &QAction::triggered, &myWindow, [QWeakPointer<MyWindow> weakWindow = myWindow]()
{
weakWindow->openDialogBox("Title","Hello, this is a message");
});
QWeakPointer is used in case your class is moved, so the "old" myWindow is a dangling pointer
If your class won't be moved, just capture myWindow.
Note that my code needs C++14 to declare a variable in the lambda capture

QT C++ download multiple files with progress total

I realized downloading multiple files, but I don't know how to implement the total progress bar of the download, that is common.
My code:
QNetworkAccessManager manager;
QList<QNetworkReply *> currentDownloads;
void MainWindow::checkUpdate()
{
QStringList files;
files << "http://cavexp.net/uploads/game/Theugry/zips/resourcepacks.zip"
<< "http://cavexp.net/uploads/game/Theugry/zips/resourcepacks.zip";
doDownload(files);
}
void MainWindow::doDownload(const QVariant& v)
{
if (v.type() == QVariant::StringList) {
foreach (QString url, v.toStringList()) {
QNetworkReply* reply = manager.get(QNetworkRequest(QUrl(url)));
connect(&manager, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateDownloadProgress(qint64, qint64)));
currentDownloads.append(reply);
}
}
}
void MainWindow::downloadFinished(QNetworkReply *reply)
{
currentDownloads.removeAll(reply);
reply->deleteLater();
}
void MainWindow::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes)
{
ui->progressBar->setMaximum(totalBytes);
ui->progressBar->setValue(bytesRead);
}
I would be grateful for any help and hints! Thank you.
You probably need to iterate over your 'currentDownloads' list and connect to each one's signal downloadProgress. Then your slot(s) will be called from all of them. In that slot(s) you'll have to sum up all information coming as parameters of QNetworkReply::downloadProgress signal.
You can create a dedicated object for each QNetworkReply instance of your currentDownloads list so that you know from to which file a coming signal belongs, but if I am not mistaking you can also use single slot for all of them and then there is a meta function in Qt that will tell you from which sender the signal came.
P.S. In response to your request for small example here is "straight-forward" approach (without using QSignalMapper or QObject::sender()):
Implement a class "ProgressListenner" something like this (beware I am writing pseudo-code and you'll need to add/fix some necessarily stuff to make it actually working):
class ProgressListenner
{
public:
ProgressListenner() : _lastKnownReceived(0), _lastKnownTotal(0){}
qint64 _lastKnownReceived;
qint64 _lastKnownTotal;
slots:
onDownloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
{
_lastKnownReceived = bytesReceived;
_lastKnownTotal = bytesTotal;
}
}
Than after your line QList<QNetworkReply *> currentDownloads; add QList<ProgressListenner*> downloadListenners;. Inside your foreach each time you are adding new QNetworkReply object to currentDownloads also:
1. create new instance of ProgressListenner and add it to downloadListenners.
2. connect signal of that particular QNetworkReply to that corresponding ProgressListenner's slot: connect(reply, SIGNAL(downloadProgress(qint64, qint64)), pListenner, SLOT(onDownloadProgress (qint64, qint64)));
This way every time some QNetworkReply will fire it's progress signal, slot of corresponding ProgressListenner will be called.
Next step is sum up numbers from all downloads. One simple way is:
1. Create one more function in ProgressListenner class and make it static (important). Let say the name of function is CommonProgress.
2. At the end of onDownloadProgress function call also call CommonProgress
3. In CommonProgress function (taking care about thread safety!) iterate over all elements of downloadListenners and sum up their _lastKnownReceived and _lastKnownTotal. Do the necessarily arithmetic... Don't forget that bytesTotal can be -1!!!

Why the QT QNetworkAccessManager example dont works in my Program ?

i would write a programm that becomes data from a Url. When i open this Url with firefox, i became a .json data. The same i would make with my qt project: Open a url, that returns the same .json data. I must use the QNetworkAccessManager, right ?
But when i use the example from the qt project site, it make a syntax error. I have make all includes.
This is the code from the example , i use the same in my project.:
QNetworkRequest request;
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
QNetworkReply *reply = manager->get(request);
manager->get(QNetworkRequest(QUrl("http://qt.nokia.com")));
request.setUrl(QUrl("http://qt.nokia.com"));
I know that this dont returns me my .json data, but at first i will can opened a url.
Why my program make a syntax error. When i delete this, my program works. ( Without parsing, but it views and the buttoncklicks works.
Thank you
It seams you got error message something like this "invalid use of 'this' in non-member function" right?
When you use *this pointer it should point to some object.
You have to do something like here:
class Request : public QObject {
Q_OBJECT
public:
Request(QObject *parent=0);
~Request();
public slots:
void replyFinished(QNetworkReply *))
private:
QNetworkAccessManager *m_manager;
}
Then in request.cpp you can do it like here:
Request::Request(QObject *parent): QObject(parent) {
m_manager = new QNetworkAccessManager(this);
QObject::connect(m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply *)));
}
Request::~Request() {
delete m_manager;
}
void Request::replyFinished(QNetworkReply *reply) {
//do_something
}
Then you can use it like here:
Request *handle = new Request():
handle->do_some_methods();
//...etc

When to delete QNetworkAccessManager pointer?

This is my code. But I am confused where should I delete m_networkManager. I can do that in
onRequestCompleted() slot but the problem is my program calls getData function frequently.
My fear is this case:
getData() is called.
Before onRequestCompleted() slot is fired, my
program calls getData() again.
onRequestCompleted() for the first getData() call gets fired.
my program deletes m_networkManager which was actually allocated other memory when getData() was called second time.
I think this situation can cause crash.
void MyApp::getData() {
QNetworkRequest request;
request.setUrl(QUrl("http://www.domain.foo"));
m_networkManager = new QNetworkAccessManager(this); // Instance variable
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onRequestCompleted(QNetworkReply *)));
m_networkManager->get(request);
}
void MyApp::onRequestCompleted(QNetworkReply *reply) {
QByteArray data = reply->readAll();
reply->deleteLater();
//m_networkManager->deleteLater();
}
Since you create new QNetworkAccessManager instance each time MyApp::getData() called, you need to manage to delete the right one in MyApp::onRequestCompleted() function. The problem in your code is that you always delete the last created QNetworkAccessManager and not the one that caused the slot call. My suggestion is following:
void MyApp::getData() {
[..]
// Not class member. Will be deleted in the slot.
QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onRequestCompleted(QNetworkReply *)));
[..]
}
void MyApp::onRequestCompleted(QNetworkReply *reply) {
QByteArray data = reply->readAll();
reply->deleteLater();
// Delete object whose signal triggered this slot.
QObject *networkManager = sender();
networkManager->deleteLater();
}

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.