Обновление Qt после ответа сети

Я работаю с создателем Qt, чтобы создать программу с графическим интерфейсом, которая принимает разные URL-адреса и будет загружать и отображать html-код.

Пользователь может добавлять различные URL-адреса в listWidget. Затем пользователь может выбрать конкретный URL-адрес и загрузить HTML-код, который будет отображаться рядом со списком URL-адресов.

Проблема, с которой я сталкиваюсь, заключается в обновлении текстовой области после получения ответа.

main.cpp - в основном просто показывает окно.

#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 — Довольно прямолинейно. Содержит объект html, который будет использоваться для запроса html с введенного веб-сайта.

#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 — это начало проблемы. Если вы посмотрите на функцию «downloadButton_clicked()», вы увидите, что она извлекает html, отправляя запрос. Однако ответ не получен до следующей строки, поэтому для текстового поля установлено значение «».

#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 — после получения ответа он сохраняет html в 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;
}

Есть ли простой способ отправить значение str в класс MainWindow после получения ответа или есть ли способ для функции onclick дождаться обновления текстовой области до тех пор, пока не будет получен ответ?


person Luke Cauthen    schedule 01.10.2012    source источник


Ответы (2)


Вы определенно не хотите ждать ответа в своей функции onClick(). Это приведет к тому, что ваша программа не будет отвечать до тех пор, пока не придет сетевой запрос (что вполне может занять «вечно»).

Один из способов атаковать это — добавить сигнал в ваш класс HtmlManager. Что-то может называться stringReceived. Затем в вашем классе mainwindow вам просто нужно добавить строку, подобную этой:

connect(html, SIGNAL(stringReceived(QString)), ui->textBrowser, SLOT(setText(QString));
person Tom W    schedule 01.10.2012
comment
Как изменить код, который вы разместили, чтобы сделать его легальным. Объект html и ui-›textbrowser относятся к разным типам. Что я могу изменить, чтобы заставить его работать? - person Luke Cauthen; 01.10.2012
comment
Это нормально, что они оба разных типов. Оба они происходят от QObject. Документация для QObject::connect находится здесь. Первый и третий аргументы являются указателями QObject. - person Tom W; 01.10.2012
comment
Ну, в приведенном выше коде они были разных типов, но я это исправил. Теперь я получаю сообщение об ошибке компоновщика, когда использую предложенный вами код. LNK2005: protected: void __thiscall HtmlManager::stringReceived(class QString) (?stringReceived@HtmlManager@@IAEXVQString@@@Z), уже определенный в htmlmanager.obj У вас есть идеи, что может быть причиной этого? - person Luke Cauthen; 02.10.2012
comment
Вы предоставили определение (тело функции) для stringReceived? Вот как сообщение об ошибке выглядит для меня. С сигналами Qt вы только объявляете их. Определение обрабатывается автоматически инструментом moc, так что вам не нужно делать это самостоятельно. Вам просто нужно поместить signals: stringReceived(QString); в свой класс HtmlManager, а затем вызвать emit stringReceived(str) внутри вашего метода replyFinished. - person Tom W; 02.10.2012
comment
Спасибо, это сработало отлично. (Я новичок в использовании Qt, поэтому извините, что вам пришлось ответить на, вероятно, очень простой вопрос) - person Luke Cauthen; 03.10.2012

QNetworkAccessManager не обеспечивает синхронный или блокирующий подход. Если вы хотите подождать, пока не будет получен ответ, вы должны ждать в локальном цикле событий, пока не будет вызван сигнал завершения ответа.

См. следующую ссылку для преобразования асинхронной операции в синхронную: http://doc.qt.digia.com/qq/qq27-responsive-guis.html

В разделе «Ожидание в локальном цикле событий» они показали пример использования QNetworkAccessManager. Вы можете использовать тот же подход с тайм-аутом и локальным циклом событий.

person cyber_raj    schedule 02.10.2012