Signal not declared in this scope/undefined reference to class::method - c++

I've been trying to sort out a custom signal in my Qt application, and I can't seem to get it to compile. Essentially I have a window with a slot to handle a button press (slotCalibrate()), and another slot to receive messages and output them to the screen via a QTextEdit (slotMessage()). Both of these functions work fine in isolation.
Here is Window.cpp, slotCalibrate() is currently sending prefabricated data to Output class. In the final design slotCalibrate() will activate a calibration process on some hardware, and the results of that will be the data sent to Output.cpp
#include "window.h"
#include "output.h"
#include <QPushButton>
#include <QTextEdit>
#include <QApplication>
#include <string>
using namespace std;
Window::Window(QWidget *parent) :
QWidget(parent)
{
setFixedSize(640, 480);
calButton = new QPushButton("Calibrate", this);
calButton->setGeometry(280, 20, 80, 30);
calButton->setToolTip("Press to zero connected transducers.");
connect(calButton, SIGNAL(clicked()), this, SLOT(slotCalibrate()));
quitButton = new QPushButton("Quit", this);
quitButton->setGeometry(550, 440, 80, 30);
connect(quitButton, SIGNAL(clicked()), QApplication::instance(), SLOT(quit()));
readout = new QTextEdit(this);
readout->setReadOnly(1);
readout->setPlainText("Testing, testing, 1, 2, 3.\n");
readout->setGeometry(10, 70, 620, 360);
}
void Window::slotCalibrate()
{
string sn[5] = {"1234", "2463", "7821", "5027", "5981"};
Output *op = new Output();
op->writeMessage(1, 5, sn);
//I also tried the following with exactly the same result
//Output op;
//op.writeMessage(1, 5, sn);
}
void Window::slotMessage(string message)
{
QString qstr = QString::fromStdString(message); //Convert from string to QString
readout->append(qstr); //Print message to screen
}
I'm trying to get the button press to call the constructor of output.cpp, and then call the function writeMessage to construct and emit a message to slotMessage in window.cpp
#include "output.h"
#include <string>
#include <sstream>
using namespace std;
Output::Output(QWidget *parent) :
QWidget(parent)
{
connect (this, SIGNAL(sendMessage(string)), parentWidget(), SLOT(slotMessage(string)));
}
//void sendMessage(string)
//{
//}
void writeMessage(int cat, int count, string sn[])
{
int i;
stringstream ss;
switch (cat)
{
case 1 : //Case where calibration of one or more nodes was successful
ss << count << " transducers were successfully calibrated.\n Their serial numbers are:";
for (i=0; i<cat; i++)
{
ss << "\n" << sn[i];
}
break;
case 2: //Case where calibration of one or more nodes failed
ss << "One or more transducers failed to calibrate.";
break;
case 3: //Case where no config file is found
ss << "WARNING! Could not find 'params.config'. The default values will be used for calibration.";
break;
}
emit sendMessage(ss.str());
}
Unfortunately, with the code exactly like this, the compiler shouts at me. It says:
'sendMessage' was not declared in this scope
I have declared sendMessage in the header file as a signal, and I was under the impression signals didn't need to be implemented in code.
Nevertheless, I decided to try implementing an empty function called sendMessage. This got rid of the compiler error, but introduced another error. When calling op.writeMessage() in window.cpp, I get the error:
"undefined reference to `Output::writeMessage(int, int, std::string*)'"
I have also tried calling writeMessage inside the Output constructor, and I get the same error.
I am thoroughly lost, and have been working on this issue for a couple of days now, so any help would be immensely appreciated.
For completeness here are the header files window.h and output.h respectively:
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <string>
class QPushButton;
class QTextEdit;
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
QTextEdit *readout;
private:
QPushButton *calButton;
QPushButton *quitButton;
signals:
public slots:
void slotCalibrate();
private slots:
void slotMessage(std::string);
};
#endif // WINDOW_H
output.h
#ifndef OUTPUT_H
#define OUTPUT_H
#include <QWidget>
#include <QObject>
#include <string>
class Output : public QWidget
{
Q_OBJECT
public:
explicit Output(QWidget *parent = 0);
void writeMessage(int, int, std::string[]);
signals:
void sendMessage(std::string);
public slots:
};
#endif // OUTPUT_H

Of course this does not work. You defined the writeMessage() function but you defined it as a global function. You must prepend an "Output::" to the definition.

Related

menu bar functionalities aren't working in Qt

so i am writing a simple video player program and i did the same steps as the lesson i am taking but when i run the program and click on functionalities like end (which is close()) and open (open file) they dont work, i used the slot triggering as per the lesson although i saw different ways of using the menubar here but i must follow this format, here is my code:
header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QVideoWidget>
#include <QStyle>
#include <QMediaPlayer>
#include <QFileDialog >
namespace Ui {
class videoWidget;
}
class videoWidget : public QMainWindow
{
Q_OBJECT
QMediaPlayer *meinPlayer;
QPushButton *playButton;
QPushButton *stopButton;
public:
explicit videoWidget(QWidget *parent = 0);
~videoWidget();
private slots:
void listeUndTitelAktualisieren();
void on_action_End_triggered();
void on_action_ffnen_triggered();
void on_action_Stop_triggered();
void on_action_PlayBack_triggered();
void on_action_Pause_triggered();
private:
Ui::videoWidget *ui;
};
#endif // MAINWINDOW_H
cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
videoWidget::videoWidget(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::videoWidget)
{
ui->setupUi(this);
meinPlayer = new QMediaPlayer(this);
meinPlayer->setMedia(QUrl::fromLocalFile("/beispiele/topologien.wmv"));
meinPlayer->play();
}
void videoWidget::listeUndTitelAktualisieren()
{
QString titel = meinPlayer->media().canonicalUrl().toLocalFile();
ui->listWidget->addItem(titel);
this->setWindowTitle("Multimedia-Player – " + titel);
connect(meinPlayer, SIGNAL(mediaChanged(QMediaContent)), this, SLOT(listeUndTitelAktualisieren()));
}
void videoWidget::on_action_End_triggered()
{
this->close();
}
void videoWidget::on_action_ffnen_triggered()
{
QFileDialog *meinDialog = new QFileDialog(this);
meinDialog->setAcceptMode(QFileDialog::AcceptOpen);
meinDialog->setWindowTitle("Datei öffnen");
meinDialog->setNameFilters(QStringList() << "Videos (*.mp4 *.wmv)" << "Audios (*.mp3)" << "Alle Dateien (*.*)");
meinDialog->setDirectory(QDir::currentPath());
meinDialog->setFileMode(QFileDialog::ExistingFile);
if (meinDialog->exec() == QDialog::Accepted) {
QString datei = meinDialog->selectedFiles().first();
meinPlayer->setMedia(QUrl::fromLocalFile(datei));
/*QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Image"), "/home/jana", tr("Video & Audio Files (*.mp3 *.mp4 *.wmv)"));
*/
meinPlayer->play();
}
}
void videoWidget::on_action_Stop_triggered()
{
meinPlayer->pause();
}
void videoWidget::on_action_PlayBack_triggered()
{
meinPlayer->play();
}
void videoWidget::on_action_Pause_triggered()
{
meinPlayer->pause();
}
am pretty sure this instruction here:
connect(meinPlayer, SIGNAL(mediaChanged(QMediaContent)), this, SLOT(listeUndTitelAktualisieren()));
is not located where it should coz you are connecting the signal toa slot INSIDE of the SLOT implementation....
try moving that to the constructor of dein videoWidget

Using Thread in GUI application

I am making a multiple game. I need to take command from client. This means I have GUI and TcpServer. So I need to work them simultaneously. I used Thread but it doesnt work. Could you please help me to find the problem?
Summarizing: Firstly player press the "online" button. Then Oyun() Gui function runs and button connected with connectPressed() function. In this function there is a thread in order to run read the client commands when Gui is working.
Firstly I used QTimer in order to take command from Client in every 1 second. But My GUI freezed. And Then I used QThread but according to my research, QThread is not proper for GUI app. So I found Qtconcurrent, QFutureWatcher and QFuture. But my thread is still not working. I should have made a mistake somewhere.
#include <QApplication>
#include <anaclass.h>
#include <player2.h>
#include <tcpserver.h>
#include <QThread>
#include <QObject>
//#include <worker.h>
AnaClass *anaclass;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
anaclass = new AnaClass();
anaclass->show();
anaclass->Giris(); //button selection page
return a.exec();
}
#include "anaclass.h"
Puan *puanlama1;
Puan *puanlama2;
player2 *yilan2;
AnaClass::AnaClass() : QGraphicsView()
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setFixedSize(800,600);
scene = new QGraphicsScene;
scene->setSceneRect(0,0,800,600);
setScene(scene);
}
void AnaClass::Giris()
{
connectButton = new Button("Online");
double cxPos = this->width()/2 - connectButton->boundingRect().width()/2;
double cyPos= 425;
connectButton->setPos(cxPos, cyPos);
connect(connectButton, SIGNAL(clicked()), this, SLOT(connectPressed()));
scene->addItem(connectButton);
}
void AnaClass::Oyun()
{
scene->clear();
puanlama1 = new Puan();
puanlama1->setDefaultTextColor(Qt::blue);
puanlama1->setPos(5, 2);
scene->addItem(puanlama1);
yilan = new Yilan();
yilan->setRect(0,0,19,19);
scene->addItem(yilan);
yilan->setFlags(QGraphicsItem::ItemIsFocusable);
yilan->setFocus();
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::blue);
yilan->setBrush(brush);
if(stringButtonName == "Player2" || stringButtonName == "Online")
{
yilan->setPos(scene->width()/2 + 60, scene->height()/2);
}
else
{
yilan->setPos(scene->width()/2, scene->height()/2);
}
if(stringButtonName == "Player2" || stringButtonName == "Online")
{
yilan->playerNumber=1;
puanlama2 = new Puan();
puanlama2->setDefaultTextColor(Qt::green);
puanlama2->setPos(700, 2);
scene->addItem(puanlama2);
yilan2 = new player2();
yilan2->setRect(0,0,19,19);
scene->addItem(yilan2);
yilan2->setFlags(QGraphicsItem::ItemIsFocusable);
yilan2->setFocus();
QBrush brush2;
brush2.setStyle(Qt::SolidPattern);
brush2.setColor(Qt::green);
yilan2->setBrush(brush2);
yilan2->setPos(scene->width()/2 - 60,scene->height()/2);
}
emit emitTcp();
}
void AnaClass::connectPressed()
{
qDebug()<<"connect basildi";
server = new TCPServer();
server->Test();
stringButtonName = connectButton->buttonName;
qDebug()<<"Gelen Veri " + server->OkunanBilgi;
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()), server, SLOT(daimaOku()), Qt::QueuedConnection);
QFuture<void> deneme = QtConcurrent::run(this, &AnaClass::emitTcp);
watcher.setFuture(deneme);
Oyun();
}
}
#ifndef ANACLASS_H
#define ANACLASS_H
#include <QGraphicsScene>
#include <QGraphicsView>
#include <yilan.h>
#include <Meyve.h>
#include <QBrush>
#include <Puan.h>
#include <player2.h>
#include <QThread>
#include <label.h>
#include <QKeyEvent>
#include <button.h>
#include <QDebug>
#include <tcpserver.h>
#include <QTime>
#include <QTimer>
#include <QMutex>
//#include <worker.h>
#include <QFuture>
#include <QtConcurrent>
#include <QFutureWatcher>
class AnaClass : public QGraphicsView
{
Q_OBJECT
public:
AnaClass();
void Giris();
void Oyun();
void timerEvent(QTimerEvent *event);
void keyPressEvent(QKeyEvent *event2);
public:
Yilan *yilan;
//QThread *thread;
QGraphicsScene *scene;
Label *label1;
Button* player1Button;
Button* player2Button;
Button* connectButton;
TCPServer *server;
QTimer *timerOnline;
public:
int k=0;
int t=0;
QString stringButtonName;
signals:
void emitTcp();
public slots:
void connectPressed();
void player1Pressed();
void player2Pressed();
};
#endif // ANACLASS_H
#define TCPSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QObject>
#include <QTimer>
class TCPServer : public QObject
{
Q_OBJECT
public:
TCPServer(QObject* parent = nullptr);
void Test();
signals:
//void emitTcp();
public slots:
void newConnection();
void daimaOku(); // always read as english
public:
QTcpServer *server;
QTcpSocket *socket;
QTimer *timerTcp;
QString OkunanBilgi;
};
#endif // TCPSERVER_H
#include "tcpserver.h"
TCPServer::TCPServer(QObject * parent) : QObject()
{
}
void TCPServer::Test()
{
server = new QTcpServer();
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
if(!server->listen(QHostAddress::Any, 1234))
{
qDebug()<<"server baslamadi";
}
else
{
qDebug()<<"server basladi";
}
//timerTcp = new QTimer();
//connect(timerTcp, SIGNAL(timeout()), this, SLOT(daimaOku()));
//emit emitTcp();
}
void TCPServer::newConnection()
{
qDebug()<<"newconnection";
socket = server->nextPendingConnection();
socket->write("Merhaba Client");
socket->flush();
socket->waitForBytesWritten(5000);
timerTcp->start(50);
}
void TCPServer::daimaOku() //alwaysread() as english
{
qDebug()<<"always read function is working";
// if(socket->state() == QAbstractSocket::ConnectedState)
// {
// qDebug()<<"Daima oku fonsiyonu soket bagli";
// socket->waitForReadyRead();
// OkunanBilgi = socket->readAll();
// qDebug()<<"Tcp daima oku :" + OkunanBilgi;
// }
}
Thank you for your comments. I solved the problem by deleting QFuture and adding connect() like below.
timerOnline = new QTimer();
connect(timerOnline, SIGNAL(timeout()), server, SLOT(daimaOku()));
timerOnline->start(500);
But I have another problem. When Client connects the server, my Gui app freezes. You can find the revised code below.
void TCPServer::daimaOku()
{
qDebug()<<"Function is running";
if(socket->state() == QAbstractSocket::UnconnectedState)
{
qDebug()<<"Socket is not connected";
}
else
{
qDebug()<<"Socket connected";
socket->waitForReadyRead();
OkunanBilgi = socket->readAll();
qDebug()<<"Tcp always read :" + OkunanBilgi;
}
}
When client is not connected, the output is:
Function is running
Socket is not connected
Socket is not connected ...
I can play the game but when client is connected, game freezes. I don't understand why.

Qt Pushbutton can not connect slot

I used the QT Designer to create a simple dialog and put a pushbutton on it. Then I added a custom slot on pressed() signal called test_button(). I see the generated code and can see that there is a setupUI function that has the following in it:
QObject::connect(pushButton, SIGNAL(clicked()), TestUIClass, SLOT(test_button()));
I have a testui.cpp and a testui.h:
#include <QtWidgets/QMainWindow>
#include "ui_testui.h"
class TestUI : public QMainWindow
{
Q_OBJECT
public:
TestUI(QWidget *parent = 0);
~TestUI();
virtual void test_button();
private:
Ui::TestUIClass ui;
};
This is the testui.cpp
#include "testui.h"
#include <QMessageBox>
TestUI::TestUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
TestUI::~TestUI()
{
}
void TestUI::test_button()
{
QMessageBox msgBox;
msgBox.setText("The document has been modified.");
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
}
My understanding is this is all I have to do, but I cant get the message box to come up.
/********************************************************************************
** Form generated from reading UI file 'testui.ui'
**
** Created by: Qt User Interface Compiler version 5.9.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_TESTUI_H
#define UI_TESTUI_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_TestUIClass
{
public:
QWidget *centralWidget;
QPushButton *pushButton;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *TestUIClass)
{
if (TestUIClass->objectName().isEmpty())
TestUIClass->setObjectName(QStringLiteral("TestUIClass"));
TestUIClass->resize(600, 400);
centralWidget = new QWidget(TestUIClass);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
pushButton = new QPushButton(centralWidget);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(120, 70, 187, 57));
TestUIClass->setCentralWidget(centralWidget);
menuBar = new QMenuBar(TestUIClass);
menuBar->setObjectName(QStringLiteral("menuBar"));
menuBar->setGeometry(QRect(0, 0, 600, 47));
TestClass->setMenuBar(menuBar);
mainToolBar = new QToolBar(TestUIClass);
mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
TestUIClass->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(EyeGazeUIClass);
statusBar->setObjectName(QStringLiteral("statusBar"));
TestUIClass->setStatusBar(statusBar);
retranslateUi(TestUIClass);
QObject::connect(pushButton, SIGNAL(clicked()), TestUIClass, SLOT(test_button()));
QMetaObject::connectSlotsByName(TestUIClass);
} // setupUi
void retranslateUi(QMainWindow *TestUIClass)
{
TestUIClass->setWindowTitle(QApplication::translate("TestUIClass", "TestUI", Q_NULLPTR));
pushButton->setText(QApplication::translate("TestUIClass", "PushButton", Q_NULLPTR));
} // retranslateUi
};
namespace Ui {
class TestUIClass: public Ui_TestUIClass {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_TestUI_H
First, you need to tell Qt that your slots actually are slots:
public slots: // or protected/private
void test_button();
There is no need for having the slot virtual...
Second, slots for 'clicked' signal are expected to accept a boolean parameter:
void test_button(bool);
For a normal push button, you can ignore the value, though.
Finally, but that's just a hint: Qt introduced with version 5 a new syntax for connecting signals/slots:
QObject::connect(pushButton, &QPushButton::clicked, theUI, &TestUIClass::test_button);
I prefer it, but it is up to you which one you use...

Can't make Signals and Slots works in Qt

I'm trying to learn C++ using Qt for some basic visual applications. I want to make something simple at start, when I push a button, I want to display a text message somewhere. Here is my code:
main.h
#ifndef MYAPP_H
#define MYAPP_H
#include <QWidget>
class QLabel;
class QString;
class MyApp : public QWidget{
public:
MyApp(QWidget *parent = 0);
protected slots:
void showIt();
private:
QString *text_msg;
QLabel *message;
};
#endif
main.cpp
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QFrame>
#include <QString>
#include <vector>
#include <string>
#include <map>
#include "main.h"
#include <fstream>
using std::map;
using std::vector;
using std::string;
using std::ofstream;
/* implementation */
MyApp::MyApp(QWidget *parent):QWidget(parent){
QString text_msg;
text_msg = "This is my first message written in C++! \n It was printed with Qt!";
setFixedSize(400, 280);
QPushButton *quit = new QPushButton(tr("Quit"), this);
quit->setGeometry(62, 40, 75, 50);
quit->setFont(QFont("Times", 18, QFont::Bold));
QPushButton *show_msg = new QPushButton(tr("Show!"), this);
show_msg->setGeometry(30,15,75,45);
show_msg->setFont(QFont("Times", 18, QFont::Bold));
//message = new QLabel();
QLabel *message = new QLabel(this);
//message->setFrameStyle(QFrame::Panel | QFrame::Sunken);
//message->setText(text_msg);
//message->setText("asdf");
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
connect(show_msg, SIGNAL(clicked()), qApp, SLOT(showIt()));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(message);
layout->addWidget(show_msg);
layout->addWidget(quit);
setLayout(layout);
ofstream myfile;
myfile.open ("example");
myfile << "Writing this to a file.\n";
myfile.close();
}
void MyApp::showIt(){
//*text_msg = "xyz";
ofstream myfile;
myfile.open ("example");
myfile << "12121212121.\n";
myfile.close();
message->setText("1234");
}
int main(int argc, char *argv[])
{
/* assign messages for output
bool result;
string key = "first", message="this is a sample text";
result = Messages::add_message(key, message);
*/
/* end */
QApplication app(argc, argv);
MyApp my_simple_app;
my_simple_app.show();
return app.exec();
}
I don't understand why the program doesn't run the slot member function. I put there a some code that should print in a file some text to know if the code inside that function will be executed and the problem is at the QLabel message, but the member function are not executed.
Anyone can help me?
Thank you.
There are 3 things that I needed to change to your code to make it work:
Firstly, in main.h you need to use the Q_OBJECT macro:
class MyApp : public QWidget {
Q_OBJECT
Secondly, in main.cxx, you need to change the connect call to the correct receiver (this instead of myApp):
connect(show_msg, SIGNAL(clicked()), this, SLOT(showIt()));
Thirdly, in main.cxx, you need to uncomment the code that creates the message label as a class member:
message = new QLabel(this);
The most important part is connecting the signal to the slot for a given object like this:
connect(object_emitting, SIGNAL(clicked()),object_receiving, SLOT(showIt()));
connect(show_msg, SIGNAL(clicked()), qApp, SLOT(showIt())); in this stainment change qApp to this and try again
that means
connect(show_msg, SIGNAL(clicked()), this, SLOT(showIt()));
im not suer if there is different between privat slots: and protected slots: but usuely I use privat slots: also u can change it and try :)

Qt Update after network reply

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?
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));
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.