i'm trying to implement a simple downloader. but i'm stucked because my reply and its header is empty.
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QtDebug>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/reply/main.qml"));
viewer.showExpanded();
QUrl url("http://www.speedtest.qsc.de/10MB.qsc");
QNetworkRequest request( url );
request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
QByteArray range;
range = "bytes=" + QByteArray::number( 0 ) + "-";
request.setRawHeader("Range", range );
QNetworkAccessManager accessManager;
QNetworkReply* reply = accessManager.get( request );
qDebug() << __FILE__ << ":" << __LINE__ << reply->size();
QList<QByteArray> headerFields = reply->rawHeaderList();
qDebug() << __FILE__ << ":" << __LINE__ << headerFields.count();
for( qint64 i = 0; 0 < headerFields.count(); i++ ) {
QString string( headerFields.at(i));
qDebug() << __FILE__ << ":" << __LINE__ << string;
}
return app.exec();
}
what do i have to do, so that my reply isn't empty anymore?
thanks in advance!
I used multiple QNetworkAccessManager, so that's what caused problems because I didn't know that I should only use one per app.
Related
Here's my code:
#include <QCoreApplication>
#include <QTextStream>
#include <iostream>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextStream out(stdout);
QString filename = "F:/temp/йцук.tx";
out << filename << endl;
const wchar_t* fn_wch = filename.toStdWString().c_str();
std::wcout << filename.toStdWString().c_str() << std::endl; //1
std::wcout << fn_wch << std::endl; //2
return a.exec();
}
The problem is rows "1" and "2" outputs different strings. But aren't they should be the same? Because I assigned fn_wch to filename.toStdWString().c_str() before that.
UPD0:
I've changed the code to prevent accessing to data of the destroyed wstring:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextStream out(stdout);
QString filename = "F:/temp/йцук.tx";
out << filename << endl;
auto wstr = filename.toStdWString();
auto wchar = wstr.c_str();
std::wcout << wchar << std::endl; //1
std::wcout << wchar << std::endl; //2
std::wcout << wstr; //3
return a.exec();
}
But problem remains the same: row 1 outputs data, but 2 and 3 doesn't.
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "russian");
QCoreApplication a(argc, argv);
QTextStream out(stdout);
QString filename = "F:/temp/йцук.tx";
out << filename << endl;
auto wstr = filename.toStdWString();
//auto wchar = wstr.c_str();
wchar_t wchar[wstr.size()];
wcscpy(wchar, wstr.c_str());
std::wcout << wchar << std::endl; //1
std::wcout << wchar << std::endl; //2
std::wcout << wstr; //3
return a.exec();
}
It works. Pointer in c_str() is destryed, so you need to copy data.
Is it "expected" for QSharedPointer::create() not to work or is it a bug? I get an error:
/usr/include/qt5/QtCore/qsharedpointer_impl.h:439:9: error:
invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
new (result.data()) T(std::forward<Args>(arguments)...);
casting from nonconst shared pointer and constructor from raw const pointer work.
I got this for Qt5.7.0 and Qt5.10.0.
Here is a minimal example:
#include <QSharedPointer>
struct A {};
int main(int argc, char *argv[])
{
auto ca = QSharedPointer<const A>::create();
return 0;
}
Here is one file (not minimal) example but with few working cases, 2 not working and a debug. Commented defines are for "not compiling" parts.
#include <QSharedPointer>
#include <QDebug>
#define FROM_PTR
//#define CONST_CREATE
#define FROM_RAW_PTR
#define PERFECT_FORWARD_CREATE
//#define PERFECT_FORWARD_CREATE_CONST
#define BUILTIN_CAST
class A
{
public:
A() = default;
A(int i) : _i{i} {}
void foo() const { qDebug() << "const foo" << _i; }
void foo() { qDebug() << "foo" << ++_i; }
private:
int _i{0};
};
using ASPtr = QSharedPointer<A>;
using ASCPtr = QSharedPointer<const A>;
int main(int argc, char *argv[])
{
Q_UNUSED(argc)
Q_UNUSED(argv)
#ifdef FROM_PTR
qDebug() << "FROM_PTR";
auto a1 = ASPtr::create();
a1->foo();
auto ca1 = static_cast<ASCPtr>(a1);
ca1->foo();
qDebug() << "\n";
#endif // FROM_PTR
#ifdef CONST_CREATE
qDebug() << "CONST_CREATE";
auto ca2 = ASCPtr::create();
ca2->foo();
qDebug() << "\n";
#endif // CONST_CREATE
#ifdef FROM_RAW_PTR
qDebug() << "FROM_RAW_PTR";
auto ca3 = ASCPtr(new const A);
ca3->foo();
qDebug() << "\n";
#endif // FROM_RAW_PTR
#ifdef PERFECT_FORWARD_CREATE
qDebug() << "PERFECT_FORWARD_CREATE";
auto a2 = ASPtr::create(10);
a2->foo();
qDebug() << "\n";
#endif // PERFECT_FORWARD_CREATE
#ifdef PERFECT_FORWARD_CREATE_CONST
qDebug() << "PERFECT_FORWARD_CREATE_CONST";
auto ca4 = ASCPtr::create(20);
ca4->foo();
qDebug() << "\n";
#endif // PERFECT_FORWARD_CREATE
#ifdef BUILTIN_CAST
qDebug() << "BUILTIN_CAST";
QSharedPointer<A> a3 = ASPtr::create();
a3->foo();
auto ca4 = a3.constCast<const A>();
ca4->foo();
qDebug() << "\n";
#endif // BUILTIN_CAST
return 0;
}
That is a known Qt bug (QTBUG-49748). Although it is marked as resolved in Qt 5.6.0, the bug is still present as pointed out in the comments.
Why is this happening?
Look at the implmentation of the class QSharedPointer qsharedpointer_impl.h.
In particular the line:
new (result.data()) T(std::forward<Args>(arguments)...);
uses the result.data() as the new expression placement params. Unfortunately, one can not use a const pointer as a placement param (have a look at this question here on SO for more details).
Hence, there's not much you can do except reporting this to Qt developers via the official bug tracker.
You may have a look at the smart pointers provided by the standard library (e.g. std::shared_ptr) if you are not forced to use Qt ones.
UPDATE
As reported in Qt bug tracker, this bug was fixed in version 5.11 (here is the related commit). Basically, they used std::remove_cv to remove the topmost const from the type specified.
While learning how to use QtRO tech preview module, I tried a simple 3 node network ( A registry node, a source object remoting node, and a client node).
registry node main.cpp:
#include <QCoreApplication>
#include <QRemoteObjectRegistryHost>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QRemoteObjectRegistryHost host(QUrl("tcp://127.0.0.1:5557"));
return a.exec();
}
source node main.cpp:
#include <QCoreApplication>
#include <QRemoteObjectHost>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTimer timer;
timer.start(10000);
QRemoteObjectHost host;
if(!host.setHostUrl(QUrl("tcp://127.0.0.1:5556"))) qDebug() << "Host url " << host.lastError();
if(!host.setRegistryUrl(QUrl("tcp://127.0.0.1:5557"))) qDebug() << "Reg url " << host.lastError();
if(!host.enableRemoting(&timer, "HostTimer")) qDebug() << "Remoting error " << host.lastError();
return a.exec();
}
client node main.cpp:
#include <QCoreApplication>
#include <QRemoteObjectNode>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QRemoteObjectNode node(QUrl("tcp://127.0.0.1:5557"));
QObject::connect(&node, &QRemoteObjectNode::remoteObjectAdded,
[](const QRemoteObjectSourceLocation& info){
qDebug() << "New source added : " << info;
});
qDebug() << "Waiting for registry ";
node.waitForRegistry(10000);
qDebug() << "Already here sources : " << node.registry()->sourceLocations();
QTimer timer;
timer.start(5000);
QObject::connect(&timer, &QTimer::timeout,
[&](){
qDebug() << "New sources list : " << node.registry()->sourceLocations();
});
return a.exec();
}
I begin by starting the registry node, then the client node and finally the source node, with this launch sequence I expect to get the remoteObjectAdded fired up, but It didn't.
Your help will be highly appreciated.
I answer my question.
I used the wrong signal source in the connect method call.
the client node will be as :
#include <QCoreApplication>
#include <QRemoteObjectNode>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QRemoteObjectNode node(QUrl("tcp://127.0.0.1:5557"));
QObject::connect(node.registry(), &QRemoteObjectRegistry::remoteObjectAdded,
[](const QRemoteObjectSourceLocation& info){
qDebug() << "New source added : " << info;
});
qDebug() << "Waiting for registry ";
node.waitForRegistry(10000);
qDebug() << "Already here sources : " << node.registry()->sourceLocations();
QTimer timer;
timer.start(5000);
QObject::connect(&timer, &QTimer::timeout,
[&](){
qDebug() << "New sources list : " << node.registry()->sourceLocations();
});
return a.exec();
}
It is the registry who fire the signal not the node, It sound logic after all the source nodes are connected to the registry, so it fire the remoteObjectAdded signal.
I need to assign a pointer to a custom class in qml using QQmlContext::setContextProperty(). Another qml object has Q_PROPERTY of the same type to retrieve it again.
A simple test showed me that the conversion does not work like i thought.
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};
Q_DECLARE_METATYPE(TestClass*)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();
auto testObject = new TestClass;
QVariant variant(qMetaTypeId<TestClass*>(), testObject);
auto test = variant.value<TestClass*>();
qDebug() << testObject << variant << test;
return 0;
}
This tiny test application gives me an output like this:
metaTypeId = 1024
TestClass::TestClass()
0x1b801e0 QVariant(TestClass*, ) 0x0
I would really like to get the same pointer out again after converting it down to a QVariant. Later I will assign it to a qml context and then the conversation must work correctly.
This works for me using Qt 5.9:
#include <QVariant>
#include <QDebug>
class CustomClass
{
public:
CustomClass()
{
}
};
Q_DECLARE_METATYPE(CustomClass*)
class OtherClass
{
public:
OtherClass()
{
}
};
Q_DECLARE_METATYPE(OtherClass*)
int main()
{
CustomClass *c = new CustomClass;
OtherClass *o = new OtherClass;
QVariant v;
v.setValue(c);
QVariant v2;
v2.setValue(o);
qDebug() << v.userType() << qMetaTypeId<CustomClass*>() << v2.userType() << qMetaTypeId<OtherClass*>();
qDebug() << v.value<CustomClass*>() << c << v2.value<OtherClass*>() << o;
return 0;
}
And the output i got:
1024 1024 1025 1025
0x81fca50 0x81fca50 0x81fca60 0x81fca60
As #thuga mentioned in the comments, you need to use void* and static_cast along with QVariant::fromValue.
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};
Q_DECLARE_METATYPE(TestClass*)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();
auto testObject = new TestClass;
QVariant variant(QVariant::fromValue(static_cast<void*>(testObject)));
auto test = static_cast<TestClass*>(variant.value<void*>());
qDebug() << testObject << variant << test;
return 0;
}
If used QTextStream console(stdout) - all work just fine, but if I wrote custom IODevice, after qInstallMsgHandler() no text in console
main.cpp
#include "remoteconsole.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QTimer>
QTextStream *out;
void logOutput(QtMsgType type, const char *msg)
{
QString debugdate = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
*out << debugdate << " " << type << msg << endl;
}
int main(int argc, char *argv[])
{
int i;
QCoreApplication a(argc, argv);
RemoteConsole * remote = new RemoteConsole(&a);
QTextStream console((QIODevice *)remote);
out = &console;
qDebug() << "start qInstallMsgHandler";
qInstallMsgHandler(logOutput);
qDebug() << "end qInstallMsgHandler"<<endl;
for(i=0;i<10;i++){
qDebug() << i<<endl;
}
QTimer *timer = new QTimer();
a.connect(timer, SIGNAL(timeout()), &a, SLOT(quit()));
timer->start(5000);
a.exec();
return 0;
}
my IODevice implementation in file remoteconsole.h .cpp
#ifndef REMOTECONSOLE_H
#define REMOTECONSOLE_H
#include <QIODevice>
#include <QDebug>
class RemoteConsole: public QIODevice
{
Q_OBJECT
public:
RemoteConsole(QObject *parent);
~RemoteConsole();
private:
Q_DISABLE_COPY(RemoteConsole)
protected:
qint64 readData(char* data, qint64 maxSize);
qint64 writeData(const char* data, qint64 maxSize);
};
#endif // REMOTECONSOLE_H
#include "remoteconsole.h"
RemoteConsole::RemoteConsole(QObject* parent=0) :
QIODevice(parent)
{
}
RemoteConsole::~RemoteConsole(){}
qint64 RemoteConsole::readData(char *data, qint64 maxlen){
qDebug() << data <<endl;
return maxlen;
}
qint64 RemoteConsole::writeData(const char *data, qint64 len){
printf("writeData");
qDebug() << data <<endl;
return len;
}
In future I want to expand this code with QTCPServer, that send debug outputs to client connected to the device by telnet or nc.
You don't get any text in console after qInstallMsgHandler call because you send all debug data into your RemoteConsole object.
Also you've got some other problems in your code.
You should call QIODevice::open before you can operate on that device.
In the RemoteConsole::writeData function you will have an infinite loop because you use qDebug() there. qDebug() will call logOutput which will call RemoteConsole::writeData again.