0 == 1 == 2 ???
-
Okay, this has to be the most ridiculously frustrating bug I have seen to date using Qt.
All I am trying to do is set up a GUI with 3 buttons, each with its own enum. If the enum is equal to Reboot (2), then the system is supposed to reboot. If the enum is 0 or 1, the process is supposed to call a different command.
Initially when I was typing "transitionTo.goToNext(transitionTo.EnumValue)", it was interpeting the int as a unicode character, which I didn't know how to deal with and didn't want to spend the time learning.
Now, I am just sending single character strings. In transition_functions.cpp, num.toInt() always prints the correct enum integer value, but whether it is 0, 1, or 2, num.compare("2") == 0 always returns true, because the reboot command executes for every button pressed!!! Extremely frustrated with this trivial code. Please help and/or shed some light on this tomfoolery.
I should also mention that the second script command is a placeholder at this point.
main.cpp:
#include "transition_functions.cpp" #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QChar> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; transition_functions *context_property = new transition_functions(); context_property->passPid(app.applicationPid()); qDebug() << transition_functions::App_ScreenTest << "," << transition_functions::App_UiTest << "," << transition_functions::Reboot; QQmlContext *context = engine.rootContext(); context->setContextProperty("transitionTo",context_property); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
transition_functions.h:
#include <QObject> #include <QProcess> #include <QString> #include <QStringList> #include <QDebug> class transition_functions: public QObject { Q_OBJECT Q_ENUMS(Next) public: enum Next { App_UiTest, App_ScreenTest, Reboot}; transition_functions(QObject *parent = nullptr): QObject(parent) { } Q_INVOKABLE void goToNext(QString num); void passPid(int val) { _appPid = val; } virtual ~transition_functions() { } int _appPid; };
transition_functions.cpp:
#include "transition_functions.h" void transition_functions::goToNext(QString num) { QProcess *proc = new QProcess(); qDebug() << "button pressed: " << num.toInt(); if (num.compare("2") == 0) { if (num.toInt() != 2) { qDebug() << "this is fucked."; } proc->start("/bin/bash",QStringList() << "-c" << "echo 'reboot' > /dev/ttyS0"); } else { QString command = "echo '. scriptpathname.sh " + QString(QString::fromStdString(std::to_string(_appPid))) + " " + num + "' > /dev/ttyS0"; //passes the pid and the chosen app based on the button press. proc->start("/bin/bash", QStringList() << "-c" << command); } }
main.qml:
Window { visible: true width: 800 height: 480 title: qsTr("thing") MainForm { anchors.fill: parent testButton.onClicked: transitionTo.goToNext("0") //App_UiTest screenButton.onClicked: transitionTo.goToNext("1") //App_ScreenTest powerButton.onClicked: transitionTo.goToNext("2") //Reboot } }
-
Hi,
A quick test shows that:
qDebug() << QString("0").compare("2") << QString("1").compare("2") << QString("2").compare("2");
returns
-2
,-1
,0
respectively.By the way, why not compare the int value since you convert it anyway ?
-
Hi,
A quick test shows that:
qDebug() << QString("0").compare("2") << QString("1").compare("2") << QString("2").compare("2");
returns
-2
,-1
,0
respectively.By the way, why not compare the int value since you convert it anyway ?
I did at one point compare int values, but now I am trying strings.
Your quick test confirms my frustration; why would the if statement
if (num.compare("2") == 0)
be true for num equal to "0", "1", & "2" ? It should be false for 2 of the cases, but it's true for all 3.
-
What do you get printed on your application output ?
-
Hi
What Qt version are you using ?
Cant reproduce eitherQString num = "2"; if (num.compare("0") == 0 ) { qDebug() << "TRUE 0"; } if (num.compare("1") == 0 ) { qDebug() << "TRUE 1"; } if (num.compare("2") == 0 ) { qDebug() << "TRUE 2"; }
says
TRUE 2 -
Okay, this has to be the most ridiculously frustrating bug I have seen to date using Qt.
All I am trying to do is set up a GUI with 3 buttons, each with its own enum. If the enum is equal to Reboot (2), then the system is supposed to reboot. If the enum is 0 or 1, the process is supposed to call a different command.
Initially when I was typing "transitionTo.goToNext(transitionTo.EnumValue)", it was interpeting the int as a unicode character, which I didn't know how to deal with and didn't want to spend the time learning.
Now, I am just sending single character strings. In transition_functions.cpp, num.toInt() always prints the correct enum integer value, but whether it is 0, 1, or 2, num.compare("2") == 0 always returns true, because the reboot command executes for every button pressed!!! Extremely frustrated with this trivial code. Please help and/or shed some light on this tomfoolery.
I should also mention that the second script command is a placeholder at this point.
main.cpp:
#include "transition_functions.cpp" #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QChar> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; transition_functions *context_property = new transition_functions(); context_property->passPid(app.applicationPid()); qDebug() << transition_functions::App_ScreenTest << "," << transition_functions::App_UiTest << "," << transition_functions::Reboot; QQmlContext *context = engine.rootContext(); context->setContextProperty("transitionTo",context_property); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
transition_functions.h:
#include <QObject> #include <QProcess> #include <QString> #include <QStringList> #include <QDebug> class transition_functions: public QObject { Q_OBJECT Q_ENUMS(Next) public: enum Next { App_UiTest, App_ScreenTest, Reboot}; transition_functions(QObject *parent = nullptr): QObject(parent) { } Q_INVOKABLE void goToNext(QString num); void passPid(int val) { _appPid = val; } virtual ~transition_functions() { } int _appPid; };
transition_functions.cpp:
#include "transition_functions.h" void transition_functions::goToNext(QString num) { QProcess *proc = new QProcess(); qDebug() << "button pressed: " << num.toInt(); if (num.compare("2") == 0) { if (num.toInt() != 2) { qDebug() << "this is fucked."; } proc->start("/bin/bash",QStringList() << "-c" << "echo 'reboot' > /dev/ttyS0"); } else { QString command = "echo '. scriptpathname.sh " + QString(QString::fromStdString(std::to_string(_appPid))) + " " + num + "' > /dev/ttyS0"; //passes the pid and the chosen app based on the button press. proc->start("/bin/bash", QStringList() << "-c" << command); } }
main.qml:
Window { visible: true width: 800 height: 480 title: qsTr("thing") MainForm { anchors.fill: parent testButton.onClicked: transitionTo.goToNext("0") //App_UiTest screenButton.onClicked: transitionTo.goToNext("1") //App_ScreenTest powerButton.onClicked: transitionTo.goToNext("2") //Reboot } }
@devDawg said in 0 == 1 == 2 ???:
qDebug() << "button pressed: " << num.toInt(); if (num.compare("2") == 0) { if (num.toInt() != 2) { qDebug() << "this is f***ed."; }
I don't really believe this code can be followed to printing the rude message if
num != "2"
(unless something is seriously wrong with your Qt).But why not use the optional parameter for http://doc.qt.io/qt-5/qstring.html#toInt
Returns 0 if the conversion fails.
If a conversion error occurs, *ok is set to false; otherwise *ok is set to true.bool ok; int result = num.toInt(&ok);
What is the value of
ok
? Because if by any chance it'sfalse
, somehow, thetoInt()
would return0
, which would result in it following your "unexpected"num.toInt() != 2
route.... -
Hi
What Qt version are you using ?
Cant reproduce eitherQString num = "2"; if (num.compare("0") == 0 ) { qDebug() << "TRUE 0"; } if (num.compare("1") == 0 ) { qDebug() << "TRUE 1"; } if (num.compare("2") == 0 ) { qDebug() << "TRUE 2"; }
says
TRUE 2@mrjj 5.9.3, unfortunately. The device that I am building the app for is configured for an older version of Qt. As for your test, I got the same result.
@JonB I never gave the optional parameter a thought, that's a very good point. I apologize for the rude message, I have just been really frustrated by this.
transition_functions.cpp:
void transition_functions::goToNext(QString num) { QProcess *proc = new QProcess(); bool ok; qDebug() << "button pressed: " << num.toInt(&ok); qDebug() << "conversion was " << ok; if (num.compare("2") == 0) { qDebug() << "reboot triggered" ; proc->start("/bin/bash",QStringList() << "-c" << "echo 'reboot' > /dev/ttyS0"); } else { QString command = "echo '. scriptpathname.sh " + QString(QString::fromStdString(std::to_string(_appPid))) + " " + num + "' > /dev/ttyS0"; //passes the pid and the chosen app based on the button press. proc->start("/bin/bash", QStringList() << "-c" << command); } }
Upon testing each button press this morning, these are the results:
pressing the App_UiTest button (0),
button pressed: 0 ok == true
pressing this button triggered a reboot, without printing the "reboot triggered" message within the if statement.
pressing the App_ScreenTest button (1),
button pressed: 1 ok == true
pressing this button also triggered a reboot, & again did not print the "reboot triggered" message within the if statement.
pressing the Reboot button (2),
button pressed: 2 ok == true reboot triggered
everything here is the same as the other 2 buttons, except we actually see the "reboot triggered" message get printed.
I am not sure what to make of these results. It is almost as if in the first 2 cases, the reboot function is being triggered without even entering the if statement.
So I modified the test slightly by commenting out all the code in the else statement, leaving only a print statement "no reboot." Now when I pressed the buttons, they behave as expected. This only happened when I commented out the
proc->start() command in the else statement. Interesting to say the least.Any thoughts?
-
@devDawg
So if I understand correctly, I see the following behaviour:-
The
num.toInt(&ok)
always succeeds, and always returns the correct number. -
The
num.compare("2")
always correctly matches "2" and only "2". The correct path of itsif ... else
is always followed. -
The above two statements are as to be expected. Whatever your problem is, it is not to do with number parsing. Any time you think it is again, isolate only the parsing code (not your actions) and verify that parsing is not at issue. It can't be. This is the answer to your question as originally posted.
-
When it follows the
if
it always correctly correctly prints the reboot message and reboots. -
But when it follows the
else
path, it does not print a reboot message (correct) but it still reboots. Though if you replace theelse
'sproc-start()
with a "no reboot" statement you get that message but no reboot.
The only conclusion is that the
else
''sproc->start()
is itself causing a reboot, whether you like it or not!Now, I don't know what might be in your
scriptpathname.sh
, maybe that causes a reboot (umm, what does it do? you haven't left areboot
in there, have you????) ... Or, writing anything to/dev/ttyS0
causes a reboot. Or, ....I can't do your debugging for you. I am confident that the number parsing is not at issue (code is following correct path), and I am confident that when the
else
path is followed whatever it does it does not "magically" execute theproc->start()
from theif
route.There is much more playing you can do to satisfy yourself about what must, or must not, be going on. For example, your two
proc->start()s
could both echo stuff into some files instead of to/dev/ttyS0
so that you can see what's going on. -
-
@devDawg
So if I understand correctly, I see the following behaviour:-
The
num.toInt(&ok)
always succeeds, and always returns the correct number. -
The
num.compare("2")
always correctly matches "2" and only "2". The correct path of itsif ... else
is always followed. -
The above two statements are as to be expected. Whatever your problem is, it is not to do with number parsing. Any time you think it is again, isolate only the parsing code (not your actions) and verify that parsing is not at issue. It can't be. This is the answer to your question as originally posted.
-
When it follows the
if
it always correctly correctly prints the reboot message and reboots. -
But when it follows the
else
path, it does not print a reboot message (correct) but it still reboots. Though if you replace theelse
'sproc-start()
with a "no reboot" statement you get that message but no reboot.
The only conclusion is that the
else
''sproc->start()
is itself causing a reboot, whether you like it or not!Now, I don't know what might be in your
scriptpathname.sh
, maybe that causes a reboot (umm, what does it do? you haven't left areboot
in there, have you????) ... Or, writing anything to/dev/ttyS0
causes a reboot. Or, ....I can't do your debugging for you. I am confident that the number parsing is not at issue (code is following correct path), and I am confident that when the
else
path is followed whatever it does it does not "magically" execute theproc->start()
from theif
route.There is much more playing you can do to satisfy yourself about what must, or must not, be going on. For example, your two
proc->start()s
could both echo stuff into some files instead of to/dev/ttyS0
so that you can see what's going on. -