0
votes

I am working with Qt creator to make a GUI program that takes in different URLs and will download and display the html code.

The user can add different URLs to a listWidget. Then the user can select a specific URL and download the html which will be displayed beside the list of URLs.

The problem I am having is getting the text area to update after the reply is received.

main.cpp - Basically just shows the window.

#include <QtGui/QApplication>
#include "mainwindow.h"
#include "htmlmanager.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h - Pretty straight forward. Contains the object html that will be used to request the html from the inputted website.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "htmlmanager.h"
#include <QString>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    HtmlManager html;

private slots:
    void on_addButton_clicked();
    void on_actionExit_triggered();
    void on_removeButton_clicked();
    void on_downloadButton_clicked();
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp - This is the beginning of the problem. If you look down at the "downloadButton_clicked()" function, you see that it fetches the html by sending a request. However, the reply isn't recieved before the next line so the text field is set to "".

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_addButton_clicked()
{
    if(!ui->lineEdit->text().isEmpty())
    {
        ui->listWidget->addItem(ui->lineEdit->text());
    }
    else
    {
        qDebug() << "Input field is empty.";
    }
}

void MainWindow::on_actionExit_triggered()
{
    //doesn't do anything right now
}

void MainWindow::on_removeButton_clicked()
{
    if(ui->listWidget->currentItem()) //If an item is selected
    {
        delete ui->listWidget->currentItem();
    }
    else
    {
        qDebug() << "No selection";
    }
}

void MainWindow::on_downloadButton_clicked()
{
    if(ui->listWidget->currentItem()) //If an item is selected
    {
        html.fetch(ui->listWidget->currentItem()->text());
        ui->textBrowser->setText(html.str);
    }
    else
    {
        qDebug() << "No selection";
    }

}

htmlmaneger.h

#ifndef HTMLMANAGER_H
#define HTMLMANAGER_H

#include <QObject>
#include <QDebug>
#include <QtNetwork>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QString>


class HtmlManager : public QObject
{
    Q_OBJECT
    public:
        HtmlManager();
        void fetch(QString Url);
        QString str;

    public slots:
        void replyFinished(QNetworkReply* pReply);

    private:
        QNetworkAccessManager* m_manager;
};

#endif // HTMLMANAGER_H

htmlmanager.cpp - Once the reply is received, it stores the html in the QString "str"

#include "htmlmanager.h"

HtmlManager::HtmlManager()
{
    m_manager = new QNetworkAccessManager(this);
    connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}
void HtmlManager::fetch(QString Url)
{
    m_manager->get(QNetworkRequest(QUrl(Url)));
    qDebug() << "Sending network request.";
}
void HtmlManager::replyFinished(QNetworkReply* pReply)
{
    qDebug() << "Recieved network reply.";
    QByteArray data=pReply->readAll();
    str = data;
}

Is there an easy way to send the value of str to the MainWindow class once the reply is received, or is there a way for the onclick function to wait to update the text area until after a reply is received?

2

2 Answers

3
votes

You definitely don't want to wait for a reply in your onClick() function. That will cause your program to be unresponsive until the network request comes it (which could very well take "forever").

One way to attack this would be to add a signal to your HtmlManager class. Something maybe called stringReceived. Then, in your mainwindow class you'd just need to add a line like this:

connect(html, SIGNAL(stringReceived(QString)), ui->textBrowser, SLOT(setText(QString));
0
votes

QNetworkAccessManager don't provide synchronous or blocking approach. If you want to wait until reply has been received you have to go for waiting in a local event loop until reply finished signal invoked.

See the following link for turning asynchronous operation into synchronous one: http://doc.qt.digia.com/qq/qq27-responsive-guis.html

In the section "Waiting in a Local Event Loop" they have shown an example using QNetworkAccessManager. You can use the same approach with timeout and local event loop.