studing sddm code from official git (https://github.com/sddm/sddm), I try to add this test code:
void UserModel::test() {
QString str1 = "Test";
qWarning("%s",str1);
}
but I have an error:
whithin this context.
what does it mean?
how should I do to intialise a new QString variable?
You're not posting the complete error, and you can't pass a QString directly to qWarning. To use the C format string, you need to convert it to the local encoding and pass a const char* to that, or better yet use the debug stream:
void UserModel::test() {
auto str1 = QStringLiteral("Test");
// preferred
qWarning() << str1;
// acceptable
qWarning("%s", str1.toLocal8Bit().constData());
}
Related
so I wrote a programm for my thesis in Qt and now i am supposed to turn it into a working web assembly, which wasnt a real problem except for the filedownload part. I rewrote my filedownload method from:
QString costumfile::read(QString filename){
QString fileName = QFileDialog::getOpenFileName(nullptr, filename, "", "Text Files (*.txt )");
QFile file(filename);
qDebug()<<filename<<"filename";
if(!file.open(QFile::ReadOnly |
QFile::Text))
{
qDebug() << " Could not open the file for reading";
return "";
}
QTextStream in(&file);
QString myText = in.readAll();
//qDebug() << myText;
file.close();
return myText;
}
To this:
QString costumfile::read(QString filename)
{
QMessageBox msgBox;
QString textUser="Open" + filename;
msgBox.setText(textUser);
msgBox.exec();
QString text="hallo";
qDebug()<<filename;
auto fileContentReady = [&](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
msgBox.setText("Error");
msgBox.exec();
} else {
text=fileContent;
qDebug()<<text<<"texstis";
return fileContent;
}
return fileContent;
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
and the problem is that the return doesnt wait for the lambda function because its asynch...
I then tried using eventloops which works fine in the Destop applikation but isnt supported in the webassembly Applikation.
So does someone have a good idea how to wait for the fileContentReady Function?
As far as I know, Qt for WebAssembly currently does not support waiting using event loops (at least Qt 6.2 does not). See Qt wiki:
"Nested event loops are not supported. Applications should not call e.g. QDialog::exec() or create a new QEventLoop object."
https://wiki.qt.io/Qt_for_WebAssembly
So you would have to modify your method to handle the asynchronous call. What I mean is that whatever you want to do with the file, you can write directly into the fileContentReady lambda you have. If this is a generic function, you can let the caller register a done callback to execute when the file is ready. Something like:
QString costumfile::read(QString filename,
const std::function<void(const QString&)>& done)
{
...
auto fileContentReady = [=](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
// Report error
} else {
text=fileContent;
qDebug()<<text<<"texstis";
done(text);
}
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
// When calling costumfile::read
read(filename, [=] (const QString& text) {
// Do something with `text`
});
Also, about the usage of QMessageBox exec(). This can also cause problems as it internally creates a nested event loop which is not yet supported in Qt for WebAssembly. Instead use the show() method.
auto msgBox = new QMessageBox();
msgBox->setText(textUser);
connect(msgBox, &QMessageBox::finished, &QMessageBox::deleteLater);
msgBox->show();
While trying to construct a QString from values from a QJsonArray, I get the following error:
error: passing 'const QString' as 'this' argument discards qualifiers [-fpermissive].
Dunno where I am getting it wrong in this code:
QString <CLASS_NAME>::getData(QString callerValue) {
QString BASE_URL = "<URL>";
QString stringToReturn = "";
QObject::connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {
QByteArray barr = reply->readAll();
QJsonParseError jpe;
QJsonDocument jdoc = QJsonDocument::fromJson(barr, &jpe);
QJsonArray synonymsArray = jdoc.array();
foreach (const QJsonValue &jv, synonymsArray) {
QJsonObject jo = jv.toObject();
QString s = jo.value("<VALUE>").toString();
stringToReturn.append(s + ", "); /* ERROR: The error above is from this line... */
}
}
);
request.setUrl(QUrl(BASE_URL + callerValue));
manager->get(request);
return stringToReturn;
}
This is another classic "I wish the world was synchronous" problem. You can't code that way. The getData method can't be written the way you want it to be. getData done that way would block, and that's quite wasteful and can lead to interesting problems - not the last of which is horrible UX.
Depending on your application, there would be several possible fixes:
redo getData in implicit continuation-passing style using coroutines and co_yield - this is the future and can be done only on the most recent compilers unless you use hacks such boost coroutines.
redo getData in explicit continuation-passing style,
redo getData in lazy style with notification when data is available,
have an explicit state machine that deals with progress of your code.
The continuation-passing style requires the least changes. Note the other fixes too - most notably that you shouldn't be using the QNetworkAccessManager's signals: you're interested only in results to this one query, not every query! Catching QNetworkAccessManager::finished signal is only useful if you truly have a central point where all or at least most frequent requests can be handled. In such a case, it's a sensible optimization: there is overhead of several mallocs to adding the first connection to a hiterto connection-free object.
void Class::getData(const QString &urlSuffix, std::function<void(const QString &)> cont) {
auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
QNetworkRequest request(QUrl(urlString));
auto *reply = m_manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [=]{
QString result;
auto data = reply->readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument::fromJson(data, &jpe);
auto const synonyms = jdoc.array();
for (auto &value : synonyms) {
auto object = value.toObject();
auto s = object.value("<VALUE">).toString();
if (!result.isEmpty())
result.append(QLatin1String(", "))
result.append(s);
}
reply->deleteLater();
cont(result);
});
}
The lazy style requires the code that uses getData to be restartable, and allows continuation-passing as well, as long as the continuation is connected to the signal:
class Class : public QObject {
Q_OBJECT
QString m_cachedData;
QNetworkAccessManager m_manager{this};
Q_SIGNAL void dataAvailable(const QString &);
...
};
QString Class::getData(const QString &urlSuffix) {
if (!m_cachedData.isEmpty())
return m_cachedData;
auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
QNetworkRequest request(QUrl(urlString));
auto *reply = m_manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [=]{
m_cachedData.clear();
auto data = reply->readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument::fromJson(data, &jpe);
auto const synonyms = jdoc.array();
for (auto &value : synonyms) {
auto object = value.toObject();
auto s = object.value("<VALUE">).toString();
if (!m_cachedData.isEmpty())
m_cachedData.append(QLatin1String(", "))
m_cachedData.append(s);
}
reply->deleteLater();
emit dataAvailable(m_cachedData);
});
return {};
}
The state machine formalizes the state progression:
class Class : public QObject {
Q_OBJECT
QStateMachine m_sm{this};
QNetworkAccessManager m_manager{this};
QPointer<QNetworkReply> m_reply;
QState s_idle{&m_sm}, s_busy{&m_sm}, s_done{&m_sm};
Q_SIGNAL void to_busy();
void getData(const QString &);
...
};
Class::Class(QObject * parent) : QObject(parent) {
m_sm.setInitialState(&s_idle);
s_idle.addTransition(this, &Class::to_busy, &s_busy);
s_done.addTransition(&s_idle);
m_sm.start();
}
void Class::getData(const QString &urlSuffix) {
static char const kInit[] = "initialized";
auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
QNetworkRequest request(QUrl(urlString));
m_reply = m_manager.get(request);
s_busy.addTransition(reply, &QNetworkReply::finished, &s_done);
to_busy();
if (!s_done.property(kInit).toBool()) {
QObject::connect(&s_done, &QState::entered, this, [=]{
QString result;
auto data = m_reply->readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument::fromJson(data, &jpe);
auto const synonyms = jdoc.array();
for (auto &value : synonyms) {
auto object = value.toObject();
auto s = object.value("<VALUE">).toString();
if (!result.isEmpty())
result.append(QLatin1String(", "))
result.append(s);
}
m_reply->deleteLater();
});
s_done.setProperty(kInit, true);
}
}
Of course it would be wrong: stringToReturn is declared as a local variable in getData, It would be const if you use [=] and it will die at time of function object's call - by finished signal , if captured by reference. Lambda expression will have a dangling reference in it.That's bad place to put variable that serves as output for this function object, that variable stops to exist on return from getData.
Function object created by lambda expression here is called after getData returned. it would be called sometime when signal is fired as a result of sent request, it's an asynchronous handler. getData IS NOT the caller of lambda in this case. Caller of lambda is signal-slot system. provided that getData doesn't call lambda explicitly, we have no guarantee that function object is returned before lifespan of local storage had come to end.
Possible remebdy here is to use a field of this, if you can guarantee that this ( <CLASS_NAME> instance) is still "alive" when finished() is fired. essentially this "getData" is unable to return that value unless you would pause it until request is done (which defeats asyncronous approach).
In fact, finished would be fired when QNetworkReply::finished would be fired, QNetworkAccessManager::get just post request and returns said reply immediately. Signal is fired when you receive data (readyRead is emitted)
how convert wstringstream to char* ?? (Language c++)
I need this conversion to use the function writeRawData of the qdatastream.h library.
Thank you very much!!
You have to use wstringstream::str() to retrieve the content of the stream.
And then depending on your need you can either convert it to a QString so that the QDataStream can handle the string for you or just write the bytes of the wstring:
void f(wstringstream &stream, QDataStream &qstream)
{
wstring content = stream.str();
QString str = QString::fromStdWString(content);
qstream << str;
}
void g(wstringstream &stream, QDataStream &qstream)
{
wstring content = stream.str();
qstream.writeRawData(static_cast<const char *>(content.c_str()), content.length() * sizeof(wchar_t));
}
wstringstream is a basic_stringstream, you could extract line, char, text from it
look at that http://www.cplusplus.com/reference/sstream/wstringstream/
and you could retreive one example from that http://www.cplusplus.com/reference/sstream/basic_stringstream/str/
I'm trying to search for a string in a text file; my aim is to write it only if it isn't already written inside my text file.
Here's my function (I don't know how to put inside the while loop):
QFile MyFile("text.txt");
MyFile.open(QIODevice::ReadWrite);
QTextStream in (&MyFile);
while(!MyFile.atEnd())
{ //do something to search string inside }
MyFile.close();
How can I do that? From Qt's Help, method "contains" works with const variable only; can I use it to look for my string?
You can do the following:
[..]
QString searchString("the string I am looking for");
[..]
QTextStream in (&MyFile);
QString line;
do {
line = in.readLine();
if (!line.contains(searchString, Qt::CaseSensitive)) {
// do something
}
} while (!line.isNull());
In case of not large file
QFile MyFile("text.txt");
MyFile.open(QIODevice::ReadWrite);
QTextStream in (&MyFile);
const QString content = in.readAll();
if( !content.contains( "String" ) {
//do something
}
MyFile.close();
To not repeat other answers in case of larger files do as vahancho suggested
Here is a function that get the translation from google translate and return the result:
QString QGoogleTranslate::translate(const QString &keyword, const QString &from, const QString &to)
{
//Locate the translation in the map
QMap<QString, QPair<QString, QString> >::iterator itr = translations.find(keyword);
if(itr != translations.end())
{
if(itr.value().first == to) {
result = itr.value().second;
return result;
}
}
//Translate URL
QString url = QString("http://translate.google.com/translate_a/t?client=t&text=%0&hl=%1&sl=%2&tl=%1&multires=1&prev=enter&oc=2&ssel=0&tsel=0&uptl=%1&sc=1").arg(keyword).arg(to).arg(from);
QNetworkAccessManager manager;
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
//Get reply from Google
do
{
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} while (!reply->isFinished());
//Convert to string
result = reply->readAll();
reply->close();
//Free memory
delete reply;
//Remove [[[" from the beginning
result = result.replace("[[[\"", "");
//Extract final translated string
result = result.mid(0, result.indexOf(",\"") - 1);
//Add the translation to the map so we don't need to make another web request for a translation
translations[keyword] = QPair<QString, QString>(to, result);
return result;
}
But as you see there's a do while loop that stops application until reply->isFinished(), and when I use SIGNAL(finished()) from QNetworkReply instead of do while loop, that's not gonna work!
How can I do that without any interruption?
Move everything after the while to a slot and connect it to reply's finished() signal, you'll need to store reply as a field.
You are going to need a new signal that emits the result.
At some point you either need a processEvents loop or return to all the way back to the thread's event loop.
If you want a "blocking" way, you may use QEventLoop:
Instead of infinite loop in your code with processEvents use following pattern:
QEventLoop loop;
connect( reply, &QNetworkReply::finished, &loop, &QEventLoop::quit );
loop.exec();
For working with responce you may use QJsonObject and other.