I'm facing an error I don't really understand.
var http = new XMLHttpRequest();
var url = "http://..........";
http.open("GET", url, true);
http.onreadystatechange = function() {
console.log("readyState=" + http.readyState);
if (http.readyState == 4) {
if (http.status == 200) {
console.log("ok");
} else {
console.log("not ok");
}
}
}
http.send();
QtCreator console log:
qml: readyState=2
qml: readyState=3
ASSERT failure in QList::at: "index out of range", file C:\Qt\5.5\mingw492_32\include/QtCore/qlist.h, line 510
In Wireshark, the request is made as expected and the page correctly downloaded. What am I doing wrong?
Edit:
I am trying to use same networkaccessmanager in C++ and QML.
I have a Login class to make a connection to a website. The I need to use the same manager to make other requests in QML.
I first thought the problem was about pointer or the way I call Login(), but with Wireshark, the login request and the one made via QML have the same session id. I deduced the problem was not that, but i'm probably wrong.
main.cpp
QQmlApplicationEngine engine;
.....
QNetworkAccessManager *networkmanager = new QNetworkAccessManager();
networkmanager = engine.networkAccessManager();
Login login(networkmanager);
login.h
.....
class Login : public QObject
{
Q_OBJECT
public:
explicit Login(QNetworkAccessManager *manager, QObject *parent = 0);
.....
private:
QNetworkAccessManager *m_manager;
.....
}
login.cpp
.....
Login::Login(QNetworkAccessManager *manager, QObject *parent) : QObject(parent)
{
m_manager = manager;
connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotRequestFinished(QNetworkReply*)));
}
.....
Related
following issue abot my code. For unserstanding reason I connect to an event stream which publish every minute the actual status of a device under the url of : "urldevice"/event-stream. I connect a slot to the signal "readyread" and will disconnect. But still I am calling the disconnect function I recieve information in the cnnected slot.
Here is my code
QNetworkRequest request(_url + "events");
request.setRawHeader("Accept", "text/event-stream");
request.setHeader(QNetworkRequest::UserAgentHeader, "Plugin");
if (_token != "") {
request.setRawHeader("accept", "*/*");
QString token = "Bearer " + _token;
request.setRawHeader("Authorization", token.toUtf8());
}
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::AlwaysNetwork); // Events shouldn't be cached
_sseReply = _sseNetworkManager->get(request);
QObject::connect(_sseReply, &QNetworkReply::readyRead, this, &streamReceived);
void streamReceived() {
if (_sseReply->error() == QNetworkReply::NoError) {
qCDebug(m_logCategory) << "streamrecieved";
} else {
qCDebug(m_logCategory) << "disconnect";
}
}
void disconnect() {
if (_sseReply->isRunning()) {
_sseReply->abort();
_sseReply->close();
_sseNetworkManager->disconnect(_sseReply,&QNetworkReply::readyRead,this,&streamReceived);
_sseNetworkManager->disconnect();
_sseReply->disconnect();
qCDebug(m_logCategory) << "isrunnung";
}
_flagStandby = true;
QObject::disconnect(_sseReply, &QNetworkReply::readyRead, this, &streamReceived);
}
after caling disconnect() I see all the time
disconnect
in my log
How do I properly disconnect from the signal???
I am creating some automated GUI tests in my application using QTest.
I can access the widgets from my application using the command:
savePushButton = mainWindow->findChild<QPushButton *>("savePushButton");
It is working fine, but now I have to click on the OK button of a QMessageBox.
I created the QMessageBox in my application like this:
if( something_wrong )
{
QMessageBox::warning(new Widget(), "Title", "Something wrong!");
}
How can I have access to this QMessageBox, and its buttons?
I found a solution on the following link: http://www.qtcentre.org/threads/31239-Testing-modal-dialogs-with-QTestLib .
It uses the command QApplication::topLevelWidgets(); to get a widget list. Then it searches for the message box widget and simulates a key enter (QTest::keyClick(mb, Qt::Key_Enter);) which closes the message box.
Example:
void MyTest::testDialog()
{
QTimer::singleShot(500, this, SLOT(timeOut()));
QVERIFY(functionThatProducesMessageBox());
}
void MyTest::timeOut()
{
QWidgetList allToplevelWidgets = QApplication::topLevelWidgets();
foreach (QWidget *w, allToplevelWidgets) {
if (w->inherits("QMessageBox")) {
QMessageBox *mb = qobject_cast<QMessageBox *>(w);
QTest::keyClick(mb, Qt::Key_Enter);
}
}
}
The header file must contain the Q_OBJECT macro to use the signals and slots mechanism.
Example:
class MyClass: public QWidget
{
Q_OBJECT
public:
...
It worked well for me since the UI (thread) is blocked when the message box appears.
Note: remember to rebuild the project when you add the Q_OBJECT macro.
It often helps to look to Qt's auto tests:
void ExecCloseHelper::timerEvent(QTimerEvent *te)
{
if (te->timerId() != m_timerId)
return;
QWidget *modalWidget = QApplication::activeModalWidget();
if (!m_testCandidate && modalWidget)
m_testCandidate = modalWidget;
if (m_testCandidate && m_testCandidate == modalWidget) {
if (m_key == CloseWindow) {
m_testCandidate->close();
} else {
QKeyEvent *ke = new QKeyEvent(QEvent::KeyPress, m_key, Qt::NoModifier);
QCoreApplication::postEvent(m_testCandidate, ke);
}
m_testCandidate = Q_NULLPTR;
killTimer(m_timerId);
m_timerId = m_key = 0;
}
}
Judging from that code, you can get the message box via QApplication::activeModalWidget(). Testing native (I'm assuming they're native) widgets is difficult, which is likely why they chose to send key events, as you don't need to know e.g. the location of the buttons for those, as you would with a mouse click.
I have this class:
class JavaScript : public QObject {
Q_OBJECT
public:
JavaScript();
bool executeFromFile(QString file);
bool enabled;
public slots:
void setEnabled( bool enabled );
bool isEnabled() const;
private:
QScriptEngine engine;
};
The methods are defined like this:
#include "javascript.h"
JavaScript::JavaScript() {
executeFromFile("test.js");
}
bool JavaScript::executeFromFile(QString file) {
QFile scriptFile(file);
if (!scriptFile.open(QIODevice::ReadOnly)) return false;
QTextStream stream(&scriptFile);
QString contents = stream.readAll();
scriptFile.close();
engine.evaluate(contents, file);
return true;
}
void JavaScript::setEnabled( bool enabled ) {
JavaScript::enabled = enabled;
}
bool JavaScript::isEnabled() const {
return enabled;
}
I’m trying to access the public slots previously defined in the header file like the documentation says:
http://doc.qt.digia.com/qt/scripting.html#making-a-c-object-available-to-scripts-written-in-qtscript
The test.js file looks like this, just like the examples of the docs:
var obj = new JavaScript();
obj.setEnabled( true );
print( "obj is enabled: " + obj.isEnabled() );
But i’m not getting anything. It seems it doesn’t find the JavaScript object. What am I missing?
Doing a simple
print(1+1)
works just fine.
EDIT: An example in the qt4 webpage implements Q_PROPERTY. I tried this, but got the same result:
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
EDIT 1: Tried implementing the initializer like this:
// javascript.h:
JavaScript(QObject *parent = 0);
// javascript.cpp:
JavaScript::JavaScript(QObject *parent) : QObject(parent) {}
Still nothing...
EDIT 2: Some examples inherits from QScriptable too:
class JavaScript : public QObject, public QScriptable {}
But that makes no difference either.
You need to create QScriptClass instead of QObject. Qt contains example of how to extend script capabilites in Qt. Take a look on Custom Script Class Example
What I think you are actually missing is adding it to the script engine.
At some point you will have to declare a script engine
QScriptEngine * engine = new QScriptEngine(this);
Then you are going to want to add your object to the engine
JavaScript* js= new JavaScript();
QScriptValue jsobj = engine->newQObject(js);
engine->globalObject().setProperty("JavaScript", jsobj );
I'm by no means an expert but I think there is something else you need to do to say
var obj = new JavaScript();
at that point you probably need to take Kamil's advice and make JavaScript a subclass of QScriptClass
I have two get QNetworkRequest.
I want to handle finished signals from different methods.
For example this is code in
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
GetUserData();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(GetUserDataCompleted(QNetworkReply*)));
GetMessages();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(GetMessagesCompleted(QNetworkReply*)));
}
This my one method
I have tried replay->deleteLater(); but same result
Please advice me something useful
void MainWindow::GetUserDataCompleted(QNetworkReply *replay)
{
if(replay->error() == QNetworkReply::NoError)
{
QString getData = replay->readAll();
QMessageBox msg;
if(getData == "1")
{
msg.setText("User Is not Exits");
}
else
{
QDomDocument doc;
if(doc.setContent(getData))
{
QDomElement domElem = doc.documentElement();
QDomNode n = domElem.firstChild();
while(!n.isNull()) {
QDomElement e = n.toElement(); // try to convert the node to an element.
if(!e.isNull()) {
msg.setText(e.namedItem("Image").childNodes().at(0).nodeValue());
msg.exec();
}
n = n.nextSibling();
}
}
replay->deleteLater();
}
}
}
You can create a RequestSender class whose role is looking after requests.
Each RequestSender object will handle one unique request. While creating the QNetworkRequest that will be sent, the RequestSender will "tag" its own request with the originatingObject attribute. This attribute indicates which object sent the request. When a RequestSender object receives a reply, it will look if it is the sender of the request via the originatingObject attribute. For further informations about originatingObject, you can refer to the documentation here : http://qt-project.org/doc/qt-4.8/qnetworkrequest.html#originatingObject
Below is an example of what you can do.
requestsender.hpp :
class RequestSender {
public:
RequestSender();
~RequestSender();
void createRequest(/* Request parameters */);
public slots:
void endRequest(QNetworkReply* replay);
};
requestsender.cpp :
RequestSender::RequestSender() {
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(endRequest(QNetworkReply*)));
}
RequestSender::~RequestSender() {
disconnect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(endRequest(QNetworkReply*)));
}
void RequestSender::createRequest(/* Request parameters */) {
QNetworkRequest * myRequest = 0;
// Build myRequest with the request parameters
myRequest->setOriginatingObject(this);
nam->get(*myRequest);
}
void RequestSender::endRequest(QNetworkReply* replay) {
if (replay->request().originatingObject() != this) {
// That's not the request sent by the object -> stop the method here !
return;
}
// Treatments on replay
}
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.
I have the following code, and I would like to add some HTTP header info along with the call. Anyway that I can do that?
void NeoAPI::call(QString apiCall) {
if (this->ApiCall.contains(apiCall)) {
QNetworkAccessManager* manager = new QNetworkAccessManager(0);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(netReplyFinished(QNetworkReply*)));
QUrl url = this->ApiCall[apiCall];
url.addQueryItem("memberid","76710"); // Set for backdoor debugging
manager->get(QNetworkRequest(url));
} else {
this->requestResultText = QString("Call %1 doesn't exist").arg(apiCall);
}
}
void NeoAPI::netReplyFinished(QNetworkReply *netReply) {
if (netReply->error() == QNetworkReply::NoError) {
this->requestResultText = netReply->readAll();
} else {
this->requestResultText = "API Call Failed";
}
QMessageBox messageBox;
messageBox.setText(this->requestResultText);
messageBox.exec();
//delete netReply;
}
Also, if I wasn't using these inside a class, what would the this in the connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(netReplyFinished(QNetworkReply*))); be?
Thanks!
Yes, see the documentation of QNetworkRequest.
You'll want to do something like:
QNetworkRequest request(url);
request.setHeader( QNetworkRequest::ContentTypeHeader, "some/type" );
request.setRawHeader("Last-Modified", "Sun, 06 Nov 1994 08:49:37 GMT");
manager->get( header );
Also, if I wasn't using these inside a
class, what would the this in the
connect(manager,
SIGNAL(finished(QNetworkReply*)),
this,
SLOT(netReplyFinished(QNetworkReply*)));
be?
It wouldn't be anything. To connect a signal to a slot, that slot must be a member function of some object. The Qt primer on signals and slots explains this.