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.
Related
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 ?
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); });
Data Appending Problem While sending the data through Namedpipe using QT
localserver.h
#ifndef LOCALSERVER_H
#define LOCALSERVER_H
#include "QLocalSocket"
#include "QLocalServer"
class QLocalSocket;
class LocalServer : public QLocalServer
{
Q_OBJECT
public:
explicit LocalServer(QObject *parent = 0);
void send(QString &msj);
QLocalSocket *mSocket;
private slots:
void receive();
private:
};
#endif // LOCALSERVER_H
localserver.cpp
#include "localserver.h"
#include "QLocalSocket"
#include "QTextStream"
#include "QMessageBox"
LocalServer::LocalServer(QObject *parent) : QLocalServer(parent)
{
mSocket = nullptr;
connect(this,&LocalServer::newConnection,[&](){
mSocket = nextPendingConnection();
});
qDebug()<<"Hello World";
}
void LocalServer::send(QString &msj)
{
qDebug()<<"Sending Data";
if(mSocket)
{
QTextStream T(mSocket);
T<<msj.toStdString().c_str();
mSocket->flush();
}
}
void LocalServer::receive()
{
qDebug()<<"Im here";
QDataStream in(mSocket);
in.setVersion(QDataStream::Qt_5_2);
mSocket->readAll();
qDebug()<<"Data Received";
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "QProcess"
#include "QTimer"
#include "QLocalSocket"
#include "localserver.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void Connection();
private slots:
void on_start_clicked();
void on_send_clicked();
void on_quit_clicked();
void detect_connection();
void connect_terminate();
void connected();
void send_data();
void receive_data();
QString RandomData();
void on_pbtn_Stop_clicked();
private:
Ui::Widget *ui;
LocalServer *mLocalServer;
QTimer *timer;
QLocalSocket *mSocket;
bool first;
QString data_received;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "QProcess"
#include "QDebug"
#include "localserver.h"
#include "QMessageBox"
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
Connection();
first = true;
}
void Widget::Connection()
{
mLocalServer = new LocalServer(this);
mLocalServer->listen("Server1");
connect(mLocalServer,SIGNAL(newConnection()),this,SLOT(detect_connection()));
first = true;
timer = new QTimer(this);
timer->setInterval(8);
connect(timer,SIGNAL(timeout()),this,SLOT(send_data()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_start_clicked()
{
timer->start();
}
void Widget::on_send_clicked()
{
timer->stop();
}
void Widget::on_quit_clicked()
{
timer->stop();
this->close();
}
void Widget::detect_connection()
{
qDebug()<<"Write Pipe Established";
mSocket = new QLocalSocket(this);
mSocket->connectToServer("Server2");
connect(mSocket,SIGNAL(disconnected()),this,SLOT(connect_terminate()));
connect(mSocket,SIGNAL(connected()),this,SLOT(connected()));
qDebug()<<"Connection Established, Ready to Read";
connect(mSocket,&QLocalSocket::readyRead, [&]() {
QTextStream T(mSocket);
ui->receivedText->addItem(T.readAll());
});
}
void Widget::connect_terminate()
{
qDebug()<<"Read Server Connection Terminated";
QString string = "Stop_Session";
mLocalServer->send(string);
ui->sentText->addItem(string);
}
void Widget::connected()
{
qDebug()<<"Socket Connected to Server";
QString s=" Connection Done ";
mLocalServer->send(s);
}
void Widget::send_data()
{
QString string = RandomData();
mLocalServer->send(string);
ui->sentText->addItem(string);
}
QString Widget::RandomData()
{
srand(time(NULL));
int random_number = rand()%(1920-0 + 1) + 0; // rand() return a number between 0 and RAND_MAX
int random_number1 = rand()%(1080-0 + 1) + 0;
int random_number2 = rand()%(10-0 + 1) + 0;
QString s="Contour,"+QString::number(random_number)+","+QString::number(random_number1)+","+QString::number(random_number2);
// Basically this data in "s" gives the actual contours detected data but am using a random generator to test the Local Server and Socket .
return s;
}
void Widget::receive_data()
{
QString string;
QTextStream T(mSocket);
T.readLine();
if(T.readAll()=="Stop")
{
qDebug()<<"Socket About to Close";
QString string = "Stop";
mLocalServer->send(string);
}
else
{
qDebug()<<"Program can continue"<<T.readAll();
}
}
void Widget::on_pbtn_Stop_clicked()
{
timer->stop();
}
At Receiver SIde Program
Receiver.cpp
void Receiver ::Declaration_Of_Server2()
{
// Declaration Of LocalServer i.e Server2
ServerIS = new LocalServer(this);
ServerIS->listen("Server2");
// Connect To a LocalSocket TO The Above LocalServer i.e Server_IS with Server_VS
connect(ServerIS,SIGNAL(newConnection()),this,SLOT(DetectConnection_WithServer1()));
}
void CoFire_MainPage::DetectConnection_WithServer1()
{
// Declaration of LocalSocket i.e Server_VS
SocketIS = new QLocalSocket(this);
SocketIS->connectToServer("Server1");
connect(SocketIS,SIGNAL(readyRead()),this,SLOT(Receiving_VS_Data()));
}
void CoFire_MainPage::Receiving_VS_Data()
{
// Receiving Vs Data From Socket "Socket_IS"
QTextStream msg(SocketIS);
QString str = msg.readLine();
qDebug()<<" VS DATA : "<<str;
}
By this am trying to send data ( example : Contour,1000,800,1 ) from one program to other program
with a speed of 1 data / 8msec but in real scenario it might even go to 1msec data transfer.
but by this at receving end every now and then incomming data is been appended
(example: Contour,1000,800,1Contour,200,400,1Contour,500,650,1 etc... ).
But actually expentected data is
1st
Contour,1000,800,1
next
Contour,200,400,1
next
Contour,500,650,1
etc....
This way the data is getting appeneded before i capture and process the data at receiver .
By this am loosing the precious information .
how do i solve this issue .
readLine() waits for an end-of-line ("\n" or "\r\n"), but in your case you do not send it, you must change to the following:
QString Widget::RandomData(){
srand(time(NULL));
int random_number = rand()%(1920-0 + 1) + 0; // rand() return a number between 0 and RAND_MAX
int random_number1 = rand()%(1080-0 + 1) + 0;
int random_number2 = rand()%(10-0 + 1) + 0;
return QString("Contour,%1,%2,%3\n")
.arg(random_number)
.arg(random_number1)
.arg(random_number2);
}
On the other hand it is not necessary to use the reference of the QString, and also it is unnecessary to use toStdString().c_str().
void LocalServer::send(const QString &msj)
{
qDebug()<<"Sending Data";
if(mSocket)
{
QTextStream T(mSocket);
T << msj;
mSocket->flush();
}
}
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.
I am doing an exercise qt console application on threading, here is the code:
// make two thread, one checking on the state of the other
//////////////////////////////////////
// main.cpp
#include "mytimer.h"
#include "mythread.h"
#include "checkthread.h"
#include <QCoreApplication>
#include <QString>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "thread 1";
mThread1.start(QThread::HighestPriority);
CheckThread mCheck(&mThread1);
mCheck.start();
return a.exec();
}
///////////////////////////////////////
// mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
class MyThread : public QThread
{
public:
MyThread();
void run();
QString name;
bool stop;
int sum;
};
#endif // MYTHREAD_H
//////////////////////////////////////
// mythread.cpp
#include "mythread.h"
MyThread::MyThread()
{
sum = 0;
}
void MyThread::run()
{
qDebug() << this->name << " running...";
for(int i=0; i<1000; i++) {
this->sum += i;
qDebug() << this->name << " counting " << sum;
this->sleep(1);
if(this->stop) {
break;
}
}
}
//////////////////////////////////////
// checkthread.h
#ifndef CHECKTHREAD_H
#define CHECKTHREAD_H
#include <QThread>
#include "mythread.h"
class CheckThread : public QThread
{
Q_OBJECT
public:
explicit CheckThread(QObject *parent = 0);
explicit CheckThread(MyThread *tocheck);
void run();
MyThread *tocheck_;
};
#endif // CHECKTHREAD_H
//////////////////////////////////////
// checkthread.cpp
#include "checkthread.h"
CheckThread::CheckThread(QObject *parent) :
QThread(parent)
{
}
CheckThread::CheckThread(MyThread *tocheck) :
tocheck_(tocheck)
{
}
void CheckThread::run() {
while(true) {
this->sleep(1);
if(tocheck_->sum > 15) {
tocheck_->stop = true;
}
}
}
The expected behavior is that mThread1 shoud count to 15 and then stop,
but instead it is stuck at 0.
Interestingly, if I add the following code into the main.cpp file, then it runs
ok:
void Write(QString Filename)
{
QFile fh(Filename);
if(!fh.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "Could not open file for writing";
return;
}
QTextStream out(&fh);
out << "hi world";
fh.flush();
fh.close();
}
void Read(QString Filename)
{
QFile fh(Filename);
if(!fh.open(QFile::ReadOnly | QFile::Text))
{
qDebug() << "Could not open file for writing";
return;
}
QTextStream in(&fh);
QString mtext = in.readAll();
qDebug() << mtext;
}
I am using qt 4.8 on a kubuntu 13.10 machine, and the ide is qt creator 3.0.1
The problem is the member var stop in mythread.h was not initialized.
But this does not explain why the Read and Write functions in main.cpp solves the problem. Very puzzling.