Getting the profile setting using QT settings - c++

I'm using the Qt settings and it saves the object into a file. it saves to a file called sessionrc.
Now I'm trying to load the object from the settings and save it back.
The problem is I can not identify the object from the settings, so that I can load all the profiles that are saved.
I'm using the following load and save functionality
void ProfileManager::loadFrom(Settings &set, bool ownGroup)
{
qDebug()<<"LOAD";
foreach (const QString &group, set.childGroups()) {
if(group == "Profile")
{
Profile *profile = new Profile();
profile->setObjectName(group);
profile->loadFrom(set);
m_Profiles << profile;
}
}
EraObject::staticLoadFrom(set, this);
}
void ProfileManager::saveTo(Settings &set, bool ownGroup, bool force)
{
EraObject::staticSaveTo(set, this, ownGroup, force);
foreach(Profile * profile, m_Profiles) {
profile->saveTo(set);
}
}
The current setting file is
[www]
Ta=20
Te=48
Texp=38
lim1=0
lim2=0
offset=0
profilename=www
[www] is the profile that is saved. but I have many of it. How would I load it back and save it correctly

// main.cpp
#include <QCoreApplication>
#include <QSettings>
#include <QVector>
#include <QDebug>
#include <QMetaProperty>
class Profile : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName )
Q_PROPERTY(QString title READ title WRITE setTitle )
public:
explicit Profile(QObject *parent = 0) : QObject(parent) {
}
QString name() const {
return name_;
}
void setName(QString name) {
name_ = name;
}
QString title() const {
return title_;
}
void setTitle(QString title) {
title_ = title;
}
void save(QSettings& settings) const {
for(int i=0; i<metaObject()->propertyCount(); ++i) {
const auto& p = metaObject()->property(i);
if(p.isStored(this)) {
settings.setValue(p.name(), property(p.name()));
}
}
}
void load(QSettings& settings) {
for(int i=0; i<metaObject()->propertyCount(); ++i) {
const auto& p = metaObject()->property(i);
if(p.isStored(this)) {
setProperty(p.name(), settings.value(p.name()));
}
}
}
private:
QString name_;
QString title_;
};
#include "main.moc"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QObject garbageCollector;
QVector<Profile*> profiles;
{
Profile* p1 = new Profile(&garbageCollector);
p1->setName("profilename1");
p1->setTitle("Profile 1");
Profile* p2 = new Profile(&garbageCollector);
p2->setName("profilename2");
p2->setTitle("Profile 2");
profiles.append(p1);
profiles.append(p2);
}
QSettings s("profiles.ini", QSettings::IniFormat);
// write profiles
{
s.beginGroup("profiles");
foreach(const Profile*p, profiles) {
s.beginGroup(p->name());
p->save(s);
s.endGroup();
}
s.endGroup();
s.sync(); // force write
}
// read profiles
{
s.beginGroup("profiles");
foreach(const QString& g, s.childGroups()) {
Profile p;
s.beginGroup(g);
p.load(s);
s.endGroup();
qDebug() << p.name();
qDebug() << p.title();
}
s.endGroup();
}
return 0;
}

Related

Undefined reference to vtable Qt - different behaviour MSVC and MINGW [duplicate]

This question already has answers here:
Undefined reference to vtable. Trying to compile a Qt project
(21 answers)
Undefined reference to vtable, Qt in Linux
(5 answers)
undefined reference to vtable when compiling a Qt hello World
(2 answers)
Closed 4 months ago.
I am working in a C++ project with configured CMake. I added a test project to the solution.
Everything compiles and run ok with MSVC 2019 but with mingw 11.2 I get numerous errors:
undefined reference to `LoginCommObj::~LoginCommObj()'
undefined reference to `BasisCommObj::~BasisCommObj()
undefined reference to `BasisCommObj::~BasisCommObj()
undefined reference to `vtable for LoginCommObj
.......
Here is the minimum reproducible example:
Project structure:
---multiround
|
------viewmodels
|
------------cancelroundviewmodel.h
------communicationobjects
|
-----------cancelroundcommobj.h
-----------cancelroundcommobj.cpp
-----------basiscommobj.h
-----------basiscommobj.cpp
-------communicationtools.h
-------communicationtools.cpp
-------gameinfo.h
-------globaldata.h
-------globalgamedata.h
-------globaluserdata.h
-------multiplayerround.cpp
-------multiplayerround.h
-------CMakeLists.txt
---tests
|
------main.cpp
------cancelroundcommobjtest.h
------cancelroundcommobjtest.cpp
------CMakeLists.txt
The source code is as follows:
multiround/CMakeLists.txt
cmake_minimum_required (VERSION 3.10)
project (libMultiRound)
cmake_policy(SET CMP0020 NEW)
cmake_policy(SET CMP0043 NEW)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 1)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_definitions(-DMAKE_MULTIPLAYERROUND_LIB)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${Qt6Widgets_INCLUDE_DIRS}
${Qt6Network_INCLUDE_DIRS}
${Qt6Core_INCLUDE_DIRS})
set(MULTIROUND_HEADR
communicationobjects/basiscommobj.h
globaldata.h
globalgamedata.h
globaluserdata.h
viewmodels/cancelroundviewmodel.h
communicationobjects/basiscommobj.h
communicationobjects/cancelroundcommobj.h
communicationtools.h
multiplayerround.h
gameinfo.h
)
set(MULTIROUND_SRCS
communicationobjects/basiscommobj.cpp
communicationobjects/cancelroundcommobj.cpp
communicationobjects/basiscommobj.cpp
communicationtools.cpp
multiplayerround.cpp
)
add_library(libMultiRound SHARED
${MULTIROUND_SRCS}
${MULTIROUND_HEADR}
)
target_link_libraries(libMultiRound
Qt6::Widgets
Qt6::Network
Qt6::Core)
multiround/viewmodels/cancelroundviewmodel.h
#ifndef __CANCEL_ROUND_VIEWMODEL__
#define __CANCEL_ROUND_VIEWMODEL__
#include <QString>
#include <QJsonObject>
struct CancelRoundViewModel {
long int m_RoundId;
long int m_GameId;
QJsonObject toJson() {
QJsonObject retVal;
retVal.insert("roundId", QString::number(m_RoundId));
retVal.insert("gameId", QString::number(m_GameId));
return retVal;
}
};
#endif
multiround/communicationobjects/basiscommobj.h
#ifndef __BASIS_COM_OBJ__
#define __BASIS_COM_OBJ__
#include <QObject>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QSettings>
#include <QWidget>
#include "globaldata.h"
class BasisCommObj : public QObject {
Q_OBJECT
public:
BasisCommObj(const QString& requestPath, const QString& actionName):
m_RequestPath(requestPath), m_ActionName(actionName), m_ParentWidget(nullptr) {
connect( m_NetworkManager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslErrorOccured(QNetworkReply*,QList<QSslError>)));
}
virtual ~BasisCommObj();
bool makeRequestBasis(bool withToken, bool fromFinishedSlot = false);
virtual bool validateReply(const QJsonObject& reply) = 0;
protected:
BasisCommObj() {}
public slots:
virtual void errorRequest(QNetworkReply::NetworkError code);
virtual void finishedRequest();
void sslErrorOccured(QNetworkReply* reply, const QList<QSslError>& errors);
protected:
bool finishRequestHelper(QJsonObject& retJson);
bool checkInt(const QJsonValue& jsonValue);
bool checkLong(const QString& stringVal);
protected:
std::vector<QNetworkReply*> m_ReplyObjectVector; //TODO: we don't need this
QNetworkReply* m_ReplyObject = nullptr;
QString m_RequestPath;
QString m_ActionName;
QJsonObject m_RequestData;
QWidget* m_ParentWidget;
QNetworkAccessManager* m_NetworkManager;
QSettings* m_Settings;
bool m_IsSinglePlayer = true;
GlobalData* m_GlobalData;
};
#endif
multiround/communicationobjects/basiscommobj.cpp
#include "basiscommobj.h"
#include <cmath>
#include <QMessageBox>
#include <QDebug>
#include <QJsonValue>
#include "communicationtools.h"
BasisCommObj::~BasisCommObj()
{
if (m_ReplyObject != nullptr)
delete m_ReplyObject;
}
//TODO: add timer to control maximum duration of request
bool BasisCommObj::makeRequestBasis(bool withToken, bool fromFinishedSlot)
{
if (m_IsSinglePlayer) {
//() << "makeRequestBasis in single player modus";
return false;
}
if ( m_ReplyObject != nullptr && m_ReplyObject->isRunning())
return false;
if ( m_ReplyObject!= nullptr) {
if (!fromFinishedSlot) {
delete m_ReplyObject;
} else { //cannot delete the reply object from finished slot
m_ReplyObjectVector.push_back(m_ReplyObject); //TODO: I don't really need this
m_ReplyObjectVector[m_ReplyObjectVector.size() - 1]->deleteLater();
}
}
if (withToken) {
m_ReplyObject = CommunicationTools::buildPostRequestWithAuth(m_RequestPath, m_Settings->value("multiplayer/serverpath").toString(), m_RequestData, m_GlobalData->m_UserData.m_AuthToken, m_NetworkManager);
} else {
m_ReplyObject = CommunicationTools::buildPostRequest(m_RequestPath, m_Settings->value("multiplayer/serverpath").toString(), m_RequestData, m_NetworkManager);
}
connect(m_ReplyObject, &QNetworkReply::finished, this, &BasisCommObj::finishedRequest);
connect(m_ReplyObject, &QNetworkReply::errorOccurred, this, &BasisCommObj::errorRequest);
return true;
}
void BasisCommObj::errorRequest(QNetworkReply::NetworkError code)
{
//qDebug() << "Error 1";
if (m_IsSinglePlayer) {
// qDebug() << "errorRequest in single player modus";
return;
}
CommunicationTools::treatCommunicationError(m_ActionName, m_ReplyObject, m_ParentWidget);
}
void BasisCommObj::finishedRequest()
{
//() << "Finished Request 1";
QJsonObject retJson;
if (!finishRequestHelper(retJson))
return;
}
bool BasisCommObj::finishRequestHelper(QJsonObject& retJson)
{
if (m_IsSinglePlayer) {
//qDebug() << "finishRequestHelper in single player modus";
return false;
}
if (m_ReplyObject == nullptr)
return false;
if (m_ReplyObject->error() != QNetworkReply::NoError) {
return false;
}
QByteArray reply = m_ReplyObject->readAll();
QString replyQString(reply);
//qDebug() << replyQString;
retJson = CommunicationTools::objectFromString(replyQString);
if (!validateReply(retJson)) {
QMessageBox msgBox(m_ParentWidget);
msgBox.setText(m_ActionName + " reply was not recognized");
msgBox.exec();
return false;
}
return true;
}
bool BasisCommObj::checkInt(const QJsonValue& jsonValue) {
double val = jsonValue.toDouble();
double fractpart, intpart;
fractpart = modf(val , &intpart);
if (fractpart < 0.000001)
return true;
return false;
}
bool BasisCommObj::checkLong(const QString& stringVal)
{
bool ok = false;
stringVal.toLong(&ok, 10);
return ok;
}
void BasisCommObj::sslErrorOccured(QNetworkReply* reply, const QList<QSslError>& errors)
{
qDebug() << "Ssl errors";
for (auto error : errors) {
qDebug() << error.errorString();
}
}
multiround/communicationobjects/cancelroundcommobj.h
#ifndef __CANCEL_ROUND_COMMOBJ__
#define __CANCEL_ROUND_COMMOBJ__
#include "basiscommobj.h"
#include "viewmodels/cancelroundviewmodel.h"
class MultiplayerRound;
class CancelRoundCommObj : public BasisCommObj {
Q_OBJECT
public:
CancelRoundCommObj(const QString& requestPath, const QString& actionName):
BasisCommObj(requestPath, actionName) {}
bool makeRequest();
bool validateReply(const QJsonObject& retJson) override;
protected:
CancelRoundCommObj() {}
public slots:
void finishedRequest() override;
signals:
void roundCancelled();
private:
CancelRoundViewModel prepareViewModel();
private:
MultiplayerRound* m_MultiRound;
friend class CancelRoundCommObjTest;
};
#endif
multiround/communicationobjects/cancelroundcommobj.cpp
#include "cancelroundcommobj.h"
#include <QMessageBox>
#include "viewmodels/cancelroundviewmodel.h"
#include "multiplayerround.h"
bool CancelRoundCommObj::makeRequest()
{
if (m_IsSinglePlayer) {
//qDebug() << "makeRequestBasis in single player modus";
return false;
}
if (m_GlobalData->m_UserData.m_UserName.isEmpty()) {
if (m_ParentWidget != nullptr) { //nullptr is in tests
QMessageBox msgBox(m_ParentWidget);
msgBox.setText("No user logged in");
msgBox.exec();
}
return false;
}
m_RequestData = prepareViewModel().toJson();
makeRequestBasis(true);
return true;
}
void CancelRoundCommObj::finishedRequest()
{
QJsonObject retJson;
if (!finishRequestHelper(retJson))
return;
//m_MultiRound->setRoundCancelled();
emit roundCancelled();
}
bool CancelRoundCommObj::validateReply(const QJsonObject& reply) {
return (reply.contains("roundId"));
}
CancelRoundViewModel CancelRoundCommObj::prepareViewModel() {
CancelRoundViewModel cancelRoundData;
cancelRoundData.m_RoundId = m_GlobalData->m_GameData.m_RoundId;
cancelRoundData.m_GameId = m_GlobalData->m_GameData.m_GameId;
return cancelRoundData;
}
multiround/communicationtools.h
#ifndef _COMMUNICATION_TOOLS__
#define _COMMUNICATION_TOOLS__
#include <QString>
#include <QNetworkReply>
#include <QJsonObject>
#include <QWidget>
class CommunicationTools {
private:
static QString localTestServerPath;
public:
static QNetworkReply* buildPostRequest(const QString& routePath, const QString& serverPath, const QJsonObject& jsonObject, QNetworkAccessManager* networkManager);
static QNetworkReply* buildPostRequestWithAuth(const QString& routePath, const QString& serverPath, const QJsonObject& jsonObject, const QByteArray& authToken, QNetworkAccessManager* networkManager);
static QJsonObject objectFromString(const QString& in);
static void treatCommunicationError(const QString& actionName, QNetworkReply* reply, QWidget* parentWidget);
};
#endif
multiround/communicationtools.cpp
#include "communicationtools.h"
#include <QJsonDocument>
#include <QMessageBox>
QString CommunicationTools::localTestServerPath = "";
QNetworkReply * CommunicationTools::buildPostRequestWithAuth(const QString& routePath, const QString& serverPath, const QJsonObject& jsonObject, const QByteArray& authToken, QNetworkAccessManager* networkManager)
{
QString requestPath = serverPath;
if (serverPath.isEmpty())
requestPath = localTestServerPath;
//qDebug() << "request to " << requestPath ;
QUrl loginRequestUrl = QUrl(requestPath + routePath);
QNetworkRequest request(loginRequestUrl);
request.setRawHeader("Content-Type", "application/fhir+json");
request.setRawHeader(QByteArray("Authorization"), authToken);
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setProtocol(QSsl::TlsV1_3);
request.setSslConfiguration(config);
//qDebug() << "prepare request" ;
QByteArray data = QJsonDocument(jsonObject).toJson();
//qDebug() << "prepare json";
return networkManager->post(request, data);
}
QNetworkReply * CommunicationTools::buildPostRequest(const QString& routePath, const QString& serverPath, const QJsonObject& jsonObject, QNetworkAccessManager* networkManager)
{
QString requestPath = serverPath;
if (serverPath.isEmpty())
requestPath = localTestServerPath;
//qDebug() << "request to " << requestPath ;
QUrl loginRequestUrl = QUrl(requestPath + routePath);
QNetworkRequest request(loginRequestUrl);
request.setRawHeader("Content-Type", "application/fhir+json");
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setProtocol(QSsl::TlsV1_3);
request.setSslConfiguration(config);
//qDebug() << "prepare request" ;
QByteArray data = QJsonDocument(jsonObject).toJson();
//qDebug() << "prepare json";
return networkManager->post(request, data);
}
QJsonObject CommunicationTools::objectFromString(const QString& in)
{
QJsonObject obj;
QJsonDocument doc = QJsonDocument::fromJson(in.toUtf8());
// check validity of the document
if(!doc.isNull()) {
if(doc.isObject()) {
obj = doc.object();
} else {
//qDebug() << "Document is not an object";
}
} else {
//qDebug() << "Invalid JSON...\n" << in;
}
return obj;
}
void CommunicationTools::treatCommunicationError(const QString& actionName, QNetworkReply* reply, QWidget* parentWidget) {
QByteArray replyBA = reply->readAll();
QString registrationReplyQString(replyBA);
QMessageBox msgBox(parentWidget);
msgBox.setText("Error when " + actionName + " " + reply->errorString() + "\n" + registrationReplyQString);
msgBox.exec();
}
multiround/multiplayerround.h
#ifndef __MULTIPLAYER_ROUND__
#define __MULTIPLAYER_ROUND__
#if defined MAKE_MULTIPLAYERROUND_LIB
#define MULTIPLAYER_EXPORT Q_DECL_EXPORT
#else
#define MULTIPLAYER_EXPORT Q_DECL_IMPORT
#endif
#include <QObject>
#include <QNetworkAccessManager>
#include <QSettings>
#include <QJsonObject>
#include <QNetworkReply>
#include <QTimer>
#include <QWidget>
#include "gameinfo.h"
#include "globaldata.h"
#include "communicationobjects/cancelroundcommobj.h"
class MULTIPLAYER_EXPORT MultiplayerRound : public QObject/*, public AbstractPlaneRound*/ {
Q_OBJECT
private:
CancelRoundCommObj* m_CancelRoundCommObj;
public:
MultiplayerRound();
~MultiplayerRound();
void cancelRound();
};
#endif
multiround/multiplayerround.cpp
#include "multiplayerround.h"
#include <QMessageBox>
#include <QJsonArray>
#include "communicationtools.h"
MultiplayerRound::MultiplayerRound()
{
m_CancelRoundCommObj = new CancelRoundCommObj("/round/cancel", "cancelling round ");
//connect(m_CancelRoundCommObj, &CancelRoundCommObj::roundCancelled, this, &MultiplayerRound::roundWasCancelled);
}
MultiplayerRound::~MultiplayerRound()
{
delete m_CancelRoundCommObj;
}
void MultiplayerRound::cancelRound()
{
m_CancelRoundCommObj->makeRequest();
}
multiround/gameinfo.h
#ifndef __GAME_INFO__
#define __GAME_INFO__
class GameInfo {
private:
bool m_IsSinglePlayer = false;
public:
GameInfo(bool isMultiplayer) { m_IsSinglePlayer = !isMultiplayer; }
void setSinglePlayer(bool singlePlayer) {
m_IsSinglePlayer = singlePlayer;
}
bool getSinglePlayer() {
return m_IsSinglePlayer;
}
};
multiround/globaldata.h
#ifndef __GLOBAL_DATA__
#define __GLOBAL_DATA__
#include "globaluserdata.h"
#include "globalgamedata.h"
struct GlobalData {
GlobalGameData m_GameData;
GlobalUserData m_UserData;
public:
void reset() {
m_GameData.reset();
m_UserData.reset();
}
};
multiround/globalgamedata.h
#ifndef __GLOBAL_GAME_DATA__
#define __GLOBAL_GAME_DATA__
#include <QString>
struct GlobalGameData {
long int m_GameId;
long int m_RoundId;
long int m_UserId;
long int m_OtherUserId;
QString m_GameName;
QString m_OtherUsername;
public:
void reset() {
m_GameId = 0;
m_RoundId = 0;
m_UserId = 0;
m_OtherUserId = 0;
m_GameName.clear();
m_OtherUsername.clear();
}
};
#endif
multiround/globaluserdata.h
#ifndef __GLOBAL_USER_DATA__
#define __GLOBAL_USER_DATA__
#include <QString>
#include <QByteArray>
struct GlobalUserData {
QString m_UserName;
QString m_UserPassword;
QByteArray m_AuthToken;
long int m_UserId;
public:
void reset() {
m_AuthToken = QByteArray(); //TODO: token expires some times
m_UserName = QString();
m_UserPassword = QString();
m_UserId = 0;
}
};
#endif
tests/CMakeLists.txt
cmake_minimum_required (VERSION 3.10)
project (commobjtest)
cmake_policy(SET CMP0020 NEW)
cmake_policy(SET CMP0043 NEW)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../multiround/
${CMAKE_CURRENT_SOURCE_DIR}/../multiround/communicationobjects
${CMAKE_CURRENT_SOURCE_DIR}/../multiround/viewmodels
#${CMAKE_CURRENT_SOURCE_DIR}/../bcrypt/
${Qt6Widgets_INCLUDE_DIRS}
${Qt6Network_INCLUDE_DIRS}
${Qt6Core_INCLUDE_DIRS}
${Qt6Network_INCLUDE_DIRS})
set(TEST_HEADR
cancelroundcommobjtest.h
#logincommobjtest.h
)
set(TEST_SRCS
cancelroundcommobjtest.cpp
#logincommobjtest.cpp
main.cpp)
enable_testing(true)
add_executable(commobjtest ${TEST_HEADR} ${TEST_SRCS})
add_test(NAME commobjtest COMMAND commobjtest)
target_link_libraries(commobjtest
libMultiRound
#libbcrypt
#libCommon
Qt6::Test
Qt6::Widgets
Qt6::Network
Qt6::Core)
tests/main.cpp
#include "cancelroundcommobjtest.h"
int main(int argc, char** argv)
{
int status = 0;
{
CancelRoundCommObjTest tc;
status |= QTest::qExec(&tc, argc, argv);
}
return status;
}
tests/cancelroundcommobjtest.h
#ifndef __CANCEL_ROUND_COMMOBJ_TEST__
#define __CANCEL_ROUND_COMMOBJ_TEST__
#include <QObject>
#include <QTest>
#include "cancelroundcommobj.h"
class CancelRoundCommObjTest : public QObject {
Q_OBJECT
private:
CancelRoundCommObj m_CommObj;
private slots:
void initTestCase();
void SinglePlayerTest();
void NoUserLoggedInTest();
void PrepareViewModelTest();
void cleanupTestCase();
};
#endif
tests/cancelroundcommobjtest.cpp
#include "cancelroundcommobjtest.h"
#include <QTest>
void CancelRoundCommObjTest::initTestCase()
{
qDebug("CancelRoundCommObjTest starts ..");
}
void CancelRoundCommObjTest::SinglePlayerTest()
{
m_CommObj.m_IsSinglePlayer = true;
QVERIFY2(m_CommObj.makeRequest() == false, "CancelRoundCommObj should abort if single player game");
}
void CancelRoundCommObjTest::NoUserLoggedInTest()
{
m_CommObj.m_IsSinglePlayer = false;
m_CommObj.m_ParentWidget = nullptr;
GlobalData* gd = new GlobalData();
gd->m_UserData.m_UserName = "";
m_CommObj.m_GlobalData = gd;
QVERIFY2(m_CommObj.makeRequest() == false, "Cannot cancel round without being logged in");
}
void CancelRoundCommObjTest::PrepareViewModelTest()
{
GlobalData* gd = new GlobalData();
gd->m_UserData.m_UserName = "testUserName";
gd->m_GameData.m_RoundId = 123L;
gd->m_GameData.m_GameId = 234L;
m_CommObj.m_GlobalData = gd;
CancelRoundViewModel viewModel = m_CommObj.prepareViewModel();
QVERIFY2(viewModel.m_GameId == 234L, "GameId was not copied to the view model");
QVERIFY2(viewModel.m_RoundId == 123L, "RoundId was not copied to the view model");
}
void CancelRoundCommObjTest::cleanupTestCase()
{
qDebug("CancelRoundCommObjTest ends ..");
}
CMakeLists.txt
cmake_minimum_required (VERSION 3.10)
project (Planes)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 1)
find_package(Qt6 COMPONENTS Core Widgets Quick Network Test)
add_subdirectory(multiround)
add_subdirectory(tests)
Does has an idea what this can be? How come this works on the Microsoft compiler and on MinGW not ?

I am getting an error on Qt, and can't figure out where I went wrong

So, I am learning my way around Q_PROPERTY, QMetaObject and QMetaProperty.
I have built a working GUI, but whenever I run the script, I get an error
Can anyone tell me what I did wrong/am doing wrong?
The QDout() function, as mentioned, is only there to display something if I successfully connected the 'Print' Button with the QDout() function.
Below I have my files that associate with the Qt Project I am working on.
This is nothing serious, only for me to learn how to do it.
qt.core.qobject.connect: QObject::connect: No such slot FileInput::writeToFile()
My Header Files:
fileinput.h
#ifndef FILEINPUT_H
#define FILEINPUT_H
#include <QWidget>
#include <QPushButton>
#include "person.h"
class FileInput : public QWidget
{
Q_OBJECT
public:
FileInput(QWidget *parent = nullptr);
void set_GUI();
public slots:
void writeToFile(QObject *obj);
void QDout(); //just a test function to test my 'connect' part
private:
QPushButton *xx;
QPushButton *pp;
};
#endif // FILEINPUT_H
person.h
#ifndef PERSON_H
#define PERSON_H
#include <QObject>
#include <QDate>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ getName WRITE setName)
Q_PROPERTY(QDate birth READ getBirth WRITE setBirth)
public:
Person();
Person(QString n, QDate d);
QString getName() const;
QDate getBirth() const;
void setName(QString n);
void setBirth(QDate d);
private:
QString name;
QDate birthDate;
};
class Product : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ getName WRITE setName)
Q_PROPERTY(double price READ getPrice WRITE setPrice)
public:
Product();
Product(QString n, double d);
QString getName() const;
double getPrice() const;
void setName(QString n);
void setPrice(double d);
private:
QString name;
double price;
};
#endif // PERSON_H
And then i have 3 .cpp files
filminput.cpp
#include "fileinput.h"
#include <QPushButton>
#include <QVBoxLayout>
#include <QMetaObject>
#include <QMetaProperty>
#include <QFile>
#include <QTextStream>
FileInput::FileInput(QWidget *parent)
: QWidget(parent)
{
}
void FileInput::set_GUI()
{
QWidget *w = new QWidget;
w->resize(250,250);
w->setWindowTitle("Q Meta Nonsence");
Product lem = Product();
lem.setName("PHIL");
lem.setPrice(16.45);
xx = new QPushButton("Exit");
pp = new QPushButton("Print");
QVBoxLayout *ll = new QVBoxLayout;
ll->addWidget(xx);
ll->addWidget(pp);
ll->setSpacing(25);
w->setLayout(ll);
w->show();
connect(xx,SIGNAL(clicked()),w,SLOT(close()));
connect(pp,SIGNAL(clicked()),this,SLOT(writeToFile(lem)));
}
void FileInput::QDout() //just prints 'success' when pressing the 'print' button
{
qDebug() << "success";
}
//this next function is supposed to write to the data.txt file
void FileInput::writeToFile(QObject *obj)
{
QFile file("C:/Users/marti/Documents/Qt/QM/data.txt");
if(!file.open(QFile::WriteOnly|QFile::Text|QFile::Append))
{
qDebug() << "Already open or there is another issue";
file.close();
}
QTextStream toFile(&file);
const QMetaObject *mo = obj->metaObject();
for(int i=mo->propertyOffset(); i<mo->propertyCount(); i++)
{
const QMetaProperty prop = mo->property(i);
QString name = prop.name();
QVariant value = prop.read(obj);
QString valStr = value.toString();
toFile << name << ": " << valStr << "\n";
}
file.close();
}
person.cpp
#include "person.h"
Person::Person()
{
name = QString();
birthDate = QDate();
}
Person::Person(QString n, QDate d)
{
name = n;
birthDate = d;
}
QString Person::getName() const
{
return name;
}
QDate Person::getBirth() const
{
return birthDate;
}
void Person::setName(QString n)
{
name = n;
}
void Person::setBirth(QDate d)
{
birthDate = d;
}
Product::Product()
{
name = QString();
price = 0.0;
}
Product::Product(QString n, double d)
{
name = n;
price = d;
}
QString Product::getName() const
{
return name;
}
double Product::getPrice() const
{
return price;
}
void Product::setName(QString n)
{
name = n;
}
void Product::setPrice(double d)
{
price = d;
}
main.cpp
#include "fileinput.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FileInput w;
w.set_GUI();
return a.exec();
}
You're using the older connect syntax which masks the problem that you're connecting a signal with no parameters to a slot that wants a parameter. To fix it use the new syntax and use a lambda to provide the extra parameter.
connect(pp, &QPushButton::clicked, this, [=](){ writeToFile(lem); });

Value lost after 2nd call of method

I have a problem with this situation (underneath) in the console.
The data is lost after passing twice in my method called in main.ccp after making the MyClass object.
main.ccp
#include <QCoreApplication>
#include <QDebug>
#include <iostream>
#include <myclass.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyClass* myClass = new MyClass();
qDebug() << "Debug part 1";
myClass->method();
qDebug() << "Debug part 2";
myClass->method();
return a.exec();
}
The result in console:
Debug part 1
0
1 ".." "0 Bytes" "26.03.2022 08:21:13"
2 "stephane/" "0 Bytes" "26.04.2022 19:48:04"
3 ".localized" "0 Bytes" "26.03.2022 08:21:13"
4 "Shared/" "0 Bytes" "26.03.2022 08:21:13"
Debug part 2
0
The sources files:
myclass.h
myclass.ccp
entrys.h
entrys.ccp
entry.h
entry.ccp
myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QString>
#include <QDateTime>
#include "entrys.h"
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = nullptr);
void method();
signals:
private:
Entrys* entrys;
};
#endif // MYCLASS_H
myclass.ccp
#include "myclass.h"
#include <iostream>
#include "myclass.h"
#include "entry.h"
#include "entrys.h"
MyClass::MyClass(QObject *parent) : QObject(parent) {
this->entrys = new Entrys();
try {
this->entrys->setDir("/Users/","L");
} catch(ErrDirNotFound &e) {
qDebug() << e.description << " " << e.what();
}
}
void MyClass::method() {
int i = 0;
qDebug() << i;
foreach(Entry *v, this->entrys->getEntrys("L")) {
i++;
qDebug() << i << v->getName() << " " << v->getSizeString(2) << " " << v->getDateLastChangeString();
}
}
entrys.h
#ifndef ENTRYS_H
#define ENTRYS_H
#include <QObject>
#include "entry.h"
struct ErrDirNotFound: public std::exception {
QString description;
const char *what() const throw() {
return "Directory not found";
}
};
class Entrys : public QObject
{
Q_OBJECT
public:
explicit Entrys(QObject *parent = nullptr);
void setDir(QString dir, QString side);
QVector<Entry*> getEntrys(QString side);
Entry* getEntry(QString side, QString key);
QString getPath(QString side);
protected:
signals:
private:
QHash<QString, QString> hash_path;
QHash<QString, QVector<Entry*>> hash_side_entry;
void setList(QString side);
};
#endif // ENTRYS_H
entrys.ccp
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <QDebug>
#include <iostream>
#include <QDateTime>
#include <QProcess>
#include "entry.h"
#include "entrys.h"
Entrys::Entrys(QObject *parent)
: QObject{parent}
{
}
void Entrys::setList(QString side) {
QVector<Entry*> vec_entry;
QString path = this->getPath(side);
QByteArray path_ba = path.toLocal8Bit();
const char* path_cstr = path_ba.constData();
struct dirent *lecture;
DIR *dir;
struct stat buf;
QString currentPath;
int row = 0;
dir = opendir(path_cstr);
if (dir == NULL) {
ErrDirNotFound e;
QString description = "Path " + path + " don't exist !";
e.description = description;
throw e;
}
while ((lecture = readdir(dir)) != NULL) {
if (strcmp(lecture->d_name, ".") != 0) {
currentPath = path + lecture->d_name;
QByteArray path_qb = currentPath.toLocal8Bit();
const char *charCurrentPath = path_qb.constData();
if ((stat(charCurrentPath, &buf)) == -1) {
qCritical() << "stat" << currentPath;
}
int size = buf.st_size;
QDateTime modif = QDateTime::fromSecsSinceEpoch(buf.st_mtime);
Entry *entry = new Entry();
if (!strcmp(lecture->d_name, "..")) {
if (this->getPath(side) != "/") {
entry->setValue(lecture->d_name, 0, modif, 0);
}
} else {
if (S_ISDIR(buf.st_mode)) {
QString qstringTemp = lecture->d_name;
qstringTemp += "/";
entry->setValue(qstringTemp, 0, modif, buf.st_mode);
} else {
entry->setValue(lecture->d_name, size, modif, buf.st_mode);
}
}
vec_entry.append(entry);
row++;
}
}
delete lecture;
closedir(dir);
this->hash_side_entry.insert(side, vec_entry);
}
void Entrys::setDir(QString dir, QString side) {
this->hash_path.insert(side, dir);
this->setList(side);
}
QVector<Entry*> Entrys::getEntrys(QString side) {
return this->hash_side_entry.take(side);
}
QString Entrys::getPath(QString side) {
return this->hash_path[side];
}
Entry* Entrys::getEntry(QString side, QString key) {
QVector<Entry*> entry = this->getEntrys(side);
for (int i = 0; i < entry.length(); i++) {
if (entry[i]->getName() == key) {
return entry[i];
}
}
return nullptr;
}
entry.h
#ifndef ENTRY_H
#define ENTRY_H
#include <QObject>
#include <QString>
#include <QDateTime>
class Entry : public QObject
{
Q_OBJECT
public:
explicit Entry(QObject *parent = nullptr);
Entry(QString name, int size_file, QDateTime date_last_change, mode_t mode);
void setValue(QString name, int size_file, QDateTime date_last_change, mode_t mode);
QString getName();
QString getSizeString(int decimals);
QString getDateLastChangeString();
signals:
private:
QString name;
int size_file;
QDateTime date_last_change;
mode_t mode;
};
#endif // ENTRY_H
entry.ccp
#include <QDateTime>
#include "entry.h"
Entry::Entry(QObject *parent)
: QObject{parent}
{
}
Entry::Entry(QString name, int size_file, QDateTime date_last_change, mode_t mode)
{
this->name = name;
this->size_file = size_file;
this->date_last_change = date_last_change;
this->mode = mode;
}
void Entry::setValue(QString name, int size_file, QDateTime date_last_change, mode_t mode)
{
this->name = name;
this->size_file = size_file;
this->date_last_change = date_last_change;
this->mode = mode;
}
QString Entry::getName()
{
return this->name;
}
QString Entry::getSizeString(int decimals) {
int bytes = this->size_file;
if (bytes == 0) return "0 Bytes";
const int K = 1024;
const QStringList SIZES = { "Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
const int I = std::floor((std::log(bytes) / std::log(K)));
int dm = decimals < 0 ? 0 : decimals;
if (I == 0) dm = 0;
return QString::number((bytes / std::pow(K, I)),'f', dm) + " " + SIZES[I];
}
QString Entry::getDateLastChangeString() {
return this->date_last_change.toString("dd.MM.yyyy hh:mm:ss");
}
Tracking through your code by eye, I find this concerning:
QVector<Entry*> Entrys::getEntrys(QString side) {
return this->hash_side_entry.take(side);
}
A bit of googling indicates that QHash's take "Removes the item with the key from the hash and returns the value associated with it." So your getEntrys is modifying your hash_side_entry - taking data out of it. Thus when your second call to method ends up calling getEntrys a second time, there's nothing in hash_side_entry anymore.

Segmentation Fault when accessing private class variable

The problem I'm having has been discussed multiple times, but I still don't understand how to fix the issue I'm having. I used to program in C++ a lot but switched over to Java for a while due to work. I'm getting back into C++ and I'm now having a lot of issues with memory management/pointers/references etc. This problem stems from that.
For context, these are files for a Qt 5.14 project that I'm working on.
The problem is that I have a private class variable named loggerLevel and the method that creates the segmentation fault error is getLevel which just returns the value of the loggerLevel. The that is supposed to be stored in the variable is an enum named Level that is defined in the header of the class.
I don't know if the problem stems from my lack of knowledge or if I am misunderstanding something about how classes work in C++, or if its something completely different. In any case, if anyone can help me out that would be great :)
--- Source code below ---
logger.cpp
#include "logger.h"
QString debugHTML = "<font color=\"gray\">";
QString infoHTML = "<font color=\"black\">";
QString warningHTML = "<font color=\"yellow\">";
QString errorHTML = "<font color=\"orange\">";
QString criticalHTML = "<font color=\"red\">";
QString endHTML = "</font><br>";
Logger::Logger(QObject *parent,
QString fileName,
QTextEdit *editor) : QObject(parent)
{
m_editor = editor;
m_showDate = true;
loggerLevel = Level::INFO;
if (!fileName.isEmpty()) {
file = new QFile;
file->setFileName(fileName);
file->open(QIODevice::Append | QIODevice::Text);
}
}
void Logger::write(const QString &value) {
QString text = value;
if (m_showDate) {
text = QDateTime::currentDateTime()
/*.toString("dd.MM.yyyy hh:mm:ss ") + text;*/
.toString("hh:mm:ss: ") + text;
}
QTextStream out(file);
out.setCodec("UTF-8");
if (file != 0) {
out << text;
} else {
//TODO: add QMessageBox here with error
}
//Adds HTML color/formatting
switch(loggerLevel)
{
case DEBUG: text = debugHTML + text; break;
case INFO: text = infoHTML + text; break;
case WARNING: text = warningHTML + text; break;
case ERROR: text = errorHTML + text; break;
case CRITICAL: text = criticalHTML + text; break;
default: text = infoHTML + text; break;
}
text = text + endHTML;
if (m_editor != 0) {
m_editor->insertHtml(text);
} else {
//TODO: add QMessageBox here with error
}
}
void Logger::write(const Level &level, const QString &value) {
Level prevLoggerLevel = Logger::getLevel();
Logger::setLevel(level);
write(value);
Logger::setLevel(prevLoggerLevel);
}
//--------Setters--------
void Logger::setLevel(const Level &level) {
loggerLevel = level;
}
void Logger::setShowDateTime(bool value) {
m_showDate = value;
}
//--------Getters--------
Logger::Level Logger::getLevel() {
return loggerLevel;
}
Logger::~Logger() {
if (file != 0) {
file->close();
}
}
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QPlainTextEdit>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
class Logger : public QObject
{
Q_OBJECT
public:
explicit Logger(QObject *parent,
QString fileName = 0,
QTextEdit *editor = 0);
~Logger();
void setShowDateTime(bool value);
enum Level
{
DEBUG,
INFO,
WARNING,
ERROR,
CRITICAL
};
private:
QFile *file;
QTextEdit *m_editor;
bool m_showDate;
Level loggerLevel;
signals:
public slots:
void write(const QString &value);
void write(const Level &level, const QString &value);
void setLevel(const Level &level);
Level getLevel();
};
#endif // LOGGER_H
MainWindow.cpp
#include <string>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingsdialog.h"
#include "logger.h"
Logger *logger;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QString logFileName = "log.txt";
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
logger->write(Logger::Level::INFO, "Logger Initilized!");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_toolButton_clicked()
{
SettingsDialog settingsDialog;
settingsDialog.setModal(true);
settingsDialog.exec();
}
//Left Side of controller
void MainWindow::on_s_leftJoystickX_Throttle_sliderMoved(int position)
{ ui->l_leftJoystickX->setText(QStringLiteral("X-Axis: %1%").arg(position)); }
void MainWindow::on_s_leftJoystickY_Throttle_sliderMoved(int position)
{ ui->l_leftJoystickY->setText(QStringLiteral("Y-Axis: %1%").arg(position)); }
void MainWindow::on_s_leftTrigger_Throttle_sliderMoved(int position)
{ ui->l_leftTrigger->setText(QStringLiteral("Trigger: %1%").arg(position)); }
void MainWindow::on_s_joystickThrottle_sliderMoved(int position)
{ ui->l_joystickThrottle->setText(QStringLiteral("Throttle: %1%").arg(position)); }
//Right Side of controller
void MainWindow::on_s_rightJoystickX_Throttle_sliderMoved(int position)
{ ui->l_rightJoystickX->setText(QStringLiteral("X-Axis: %1%").arg(position)); }
void MainWindow::on_s_rightJoystickY_Throttle_sliderMoved(int position)
{ ui->l_rightJoystickY->setText(QStringLiteral("Y-Axis: %1%").arg(position)); }
void MainWindow::on_s_rightTrigger_Throttle_sliderMoved(int position)
{ ui->l_rightTrigger->setText(QStringLiteral("Trigger: %1%").arg(position)); }
void MainWindow::on_s_keyboardThrottle_sliderMoved(int position)
{ ui->l_keyboardThrottle->setText(QStringLiteral("Throttle: %1%").arg(position)); }
void MainWindow::on_b_keyboardAction_1_clicked()
{
logger->write(Logger::Level::CRITICAL, "test");
}
There are more files, but I believe they are not relevant to the problem, if needed I can post the other files aswell.
-----Solution!-----
#churill Solution explains what needs to be done to fix this problem but I also will detail it below to complete this question.
Since I had already made a forward declaration of logger
Logger *logger
at the top of MainWindow.cpp, creating a new Logger object
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
is unnecessary so calling the forward declarations variable name instead of creating a new Logger object
logger = new Logger(this, logFileName, ui->loggerOutput);
fixes the problem!
From first glance:
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
creates an object that has nothing to do with the global variable logger which is never initialized. Maybe you meant to write only
logger = new Logger(this, logFileName, ui->loggerOutput);
to initialize this global variable.
To somewhat address the title of your question: Yes you actually can call functions on invalid pointers, but then the this-pointer is not valid, thus accessing a member variable causes the seg-fault.

How to interact with a child QProcess?

In my program I have a child process that interacts with a serial port specified to it when the parent process demands it. For example the parent process commands the child process to read a number of bytes with a certain time out from the opened port by sending this command: read 100 1000. The child process launches and opens the port successfully and I can see the message port openned successfully! but from there onwards it won't read the parent commands.
Here's the child source code:
SerialPortHandler.h
#ifndef SERIALPORTHANDLER_H
#define SERIALPORTHANDLER_H
#include <QObject>
#include <QSocketNotifier>
#include <QTextStream>
#include <QSerialPort>
#include <QFile>
#include <QTimer>
#include <QDebug>
#include <QtCore>
enum CommandType { READ, WRITE, BAD, UNKNOWN };
class SerialPortHandler : public QObject
{
Q_OBJECT
public:
explicit SerialPortHandler(QString portname, QString baudrate, QObject *parent = 0);
signals:
public slots:
void execmd();
bool open(const QString& portname, const QString& baudrate);
qint64 read(char * buff, const qint64 size, const qint32 timeout);
QString convertToCaseInsensitiveRegExp(QString str);
CommandType analyze(const QString& line);
qint64 getNum(const QString &line, int index);
void reply(char *buff);
private:
QSocketNotifier *innotif;
QSerialPort *sp;
QTimer *timer;
};
#endif // SERIALPORTHANDLER_H
SerialPortHandler.cpp
#include "SerialPortHandler.h"
#include <unistd.h>
#include <limits>
SerialPortHandler::SerialPortHandler(QString portname, QString baudrate, QObject *parent) :
QObject(parent)
{
timer = new QTimer(this);
sp = new QSerialPort(this);
if(!open(portname, baudrate)) {
qDebug() << sp->error() << sp->errorString();
exit(sp->error());
}
innotif = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read, this);
connect(innotif, SIGNAL(activated(int)), this, SLOT(execmd()));
}
void SerialPortHandler::execmd()
{
qDebug() << "command received. analyzing...";
// qint64 nbr = -1, size = -1;
// qint32 timeout = -1;
// char * buff = 0;
// QTextStream in(stdin);
// QString ln = in.readAll();
// switch (analyze(ln)) {
// case READ:
// size = getNum(ln, 1);
// timeout = getNum(ln, 2);
// if(size > -1 && timeout > -1)
// nbr = read(buff, size, timeout);
// if(nbr > -1)
// reply(buff);
// break;
// default:
// break;
// }
}
bool SerialPortHandler::open(const QString &portname, const QString &baudrate)
{
sp->setPortName(portname);
if (!sp->open(QIODevice::ReadWrite) ||
!sp->setBaudRate(baudrate.toInt()) ||
!sp->setDataBits(QSerialPort::Data8) ||
!sp->setParity(QSerialPort::NoParity) ||
!sp->setStopBits(QSerialPort::OneStop) ||
!sp->setFlowControl(QSerialPort::NoFlowControl)) {
return false;
}
sp->clear();
qDebug() << "port openned successfully!";
return true;
}
//day light wont affect this timer so the system wont freeze
qint64 SerialPortHandler::read(char *buff, const qint64 size, const qint32 timeout)
{
qint64 numbytesread = -1;
timer->start(timeout);
while (true) {
if(timer->remainingTime() > 0) {
return -1;
}
if((sp->isReadable() && sp->bytesAvailable() > 0) ||
(sp->isReadable() && sp->waitForReadyRead(10))) {
numbytesread += sp->read(buff, size);
}
if(numbytesread < 0) {
return -1;
}
if(numbytesread == size) {
break;
}
}
return numbytesread;
}
void SerialPortHandler::notify()
{
}
QString SerialPortHandler::convertToCaseInsensitiveRegExp(QString str)
{
QString result;
for(int i = 0 ; i < str.size() ; ++i) {
result.append("[");
result.append(str.at(i).toLower());
result.append(str.at(i).toUpper());
result.append("]");
}
return result;
}
CommandType SerialPortHandler::analyze(const QString &line)
{
QString read, write;
read = convertToCaseInsensitiveRegExp("read");
write = convertToCaseInsensitiveRegExp("write");
if(line.contains(QRegExp(QString("^.*%1\\s+[1-9]\\d*\\s+[1-9]\\d*.*").arg(read)))) {
return READ;
}
return UNKNOWN;
}
qint64 SerialPortHandler::getNum(const QString& line, int index) {
QStringList args(line.split(QRegExp("\\s+")));
bool done;
qint64 size = args.at(index).toInt(&done, 10);
if(done) {
return size;
}
return -1;
}
void SerialPortHandler::reply(char * buff) {
QDataStream out(stdout);
out << buff;
}
main.cpp
#include <QCoreApplication>
#include <QDebug>
#include "SerialPortHandler.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if(argc != 3) {
qDebug() << "usage:" << argv[0] << "port" << "baudrate";
} else {
SerialPortHandler *sph = new SerialPortHandler(argv[1], argv[2]);
}
return a.exec();
}
My parent process consists of the following:
ParentProcess.h
#ifndef PARENTPROCESS_H
#define PARENTPROCESS_H
#include <QObject>
#include <QtCore>
class ParentProcess : public QObject
{
Q_OBJECT
public:
explicit ParentProcess(QObject *parent = 0);
signals:
public slots:
private slots:
void sendRead();
void writeSomething();
void handleError(QProcess::ProcessError error);
private:
QProcess *p;
};
#endif // PARENTPROCESS_H
ParentProcess.cpp
#include "ParentProcess.h"
#include <QDebug>
ParentProcess::ParentProcess(QObject *parent) :
QObject(parent)
{
p = new QProcess(this);
connect(p, SIGNAL(readyReadStandardOutput()), this, SLOT(sendRead()));
connect(p, SIGNAL(readyReadStandardError()), this, SLOT(sendRead()));
connect(p, SIGNAL(started()), this, SLOT(writeSomething()));
connect(p, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleError(QProcess::ProcessError)));
QStringList args;
args << "/dev/ttyUSB0" << "115200";
p->start("/home/moki/Work/Programs/build-serialio-Desktop_Qt_5_3_0_GCC_64bit-Debug/serialio", args, QProcess::ReadWrite);
}
void ParentProcess::sendRead() {
qDebug() << "data:" << p->readAllStandardError() << p->readAllStandardOutput();
}
void ParentProcess::writeSomething() {
qDebug() << "writing";
QString cmd = "read 10 10000\n";
qint64 a = p->write(cmd.toStdString().c_str());
qDebug() << "wrote:" << a;
}
void ParentProcess::handleError(QProcess::ProcessError error)
{
switch (error) {
case QProcess::FailedToStart:
qDebug() << "failed to start";
break;
case QProcess::Crashed:
qDebug() << "crashed.";
break;
default:
break;
}
}
main.cpp
#include <QCoreApplication>
#include "ParentProcess.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ParentProcess p;
return a.exec();
}
I have seen a couple of other answers in SO but none of them address my issue. As you can see my child process is not supposed to complete and exit. It will remain launched as long as the parent process wishes. Is it correct to use QProcess-launched processes this way?
I changed my code to the following and now it's working. But I haven't understood why this code works and my original one doesn't.
in the parent process source i changed the constructor as follows:
ParentProcess::ParentProcess(QObject *parent) :
QObject(parent)
{
p = new QProcess(this);
connect(p, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleError(QProcess::ProcessError)));
connect(p, SIGNAL(readyRead()), this, SLOT(sendRead()));
connect(p, SIGNAL(started()), this, SLOT(writeSomething()));
QStringList args;
args << "/dev/ttyUSB0" << "115200";
p->setProcessChannelMode(QProcess::MergedChannels);
p->start("/home/moki/Work/Programs/build-serialio-Desktop_Qt_5_3_0_GCC_64bit-Debug/serialio", args, QProcess::ReadWrite);
}
and the sendRead() function to this:
void ParentProcess::sendRead() {
int bytes = p->bytesAvailable();
qDebug() << "data:" << p->read(bytes);
}
finally, the writeSomething() to:
void ParentProcess::writeSomething() {
qDebug() << "gonna write.";
if(p->state() == QProcess::Running) {
qDebug() << "writing";
QString cmd = "read 10 10000\n";
qint64 a = p->write(cmd.toStdString().c_str());
qDebug() << "wrote:" << a << "bytes.";
}
}
and now it works. If anyone could please explain this to me, I would be really grateful.