Qt Message Handler crashes if installed on separate class? - c++

Whenever there is a message sent to my custom message handler, it is crashing the application at the marked line through a segmentation fault error.
// main.cpp
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QStringList data;
data.append(context.category);
data.append(context.file);
data.append(context.function);
data.append(QString(context.line));
data.append(QString(context.version));
Logger::get_obj()->myMessageOutput(type, data, msg);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("MyApp");
a.setWindowIcon(QIcon(":/Icons/MyApp.png"));
Logger log;
qInstallMessageHandler(myMessageOutput);
log.turnOnDebug();
MySplashScreen splash;
splash.show();
a.processEvents();
...
splash.close();
MainWindow *w = new MainWindow();
int errorCode = a.exec();
delete w;
session.destruct();
qDebug() << "\n*** Application exited with error code " << errorCode << " ***";
return errorCode;
}
// logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QFile>
#include <QTextStream>
#include <QMutex>
class Logger : public QObject
{
Q_OBJECT
public:
void myMessageOutput(QtMsgType type, QStringList context, const QString msg);
explicit Logger(QObject *parent = 0);
~Logger();
static Logger *get_obj() {return ptr;}
static void turnOnDebug() {get_obj()->debugMode = true;}
static void turnOffDebug() {get_obj()->debugMode = false;}
static void moveLogToSession(QString sessionName);
private:
QFile *logFile;
QTextStream *stream;
QMutex *mutex;
bool debugMode;
bool errorMsg;
static Logger *ptr;
void write(QString str);
signals:
void SaveSession();
void FatalSaveSession();
public slots:
};
#endif // LOGGER_H
// logger.cpp
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QApplication>
#include "logger.h"
#include "systemvariables.h"
Logger *Logger::ptr = NULL;
Logger::Logger(QObject *parent) : QObject(parent)
{
logFile = NULL;
stream = NULL;
mutex = NULL;
debugMode = false;
errorMsg = false;
ptr = this;
QString path = SystemVariables::getAppData();
QDir dir = QDir(path);
if(dir.exists())
{
path.append("/MyApp/Logs");
dir = QDir(path);
if(!dir.exists())
dir.mkpath(path);
logFile = new QFile(path + "/Session.log");
if(logFile->exists())
logFile->remove();
if(!logFile->open(QFile::WriteOnly | QFile::Text))
{
qFatal("Could not create log file.");
}
stream = new QTextStream(logFile);
stream->setRealNumberNotation(QTextStream::SmartNotation);
stream->setRealNumberPrecision(15);
*stream << "*** MyApp Session Begins ***\n";
}
else
qFatal("Could not create log file.");
mutex = new QMutex();
}
void Logger::myMessageOutput(QtMsgType type, QStringList context, const QString msg)
{
mutex->lock();
QString str = "";
switch (type)
{
case QtDebugMsg:
if(!debugMode)
{
mutex->unlock();
return;
}
write(msg);
break;
case QtInfoMsg:
str.append("\n*** Information ***\n");
str.append(msg + "\n");
str.append("Category: " + context.at(0) + "\n");
str.append("File: " + context.at(1) + "\n");
str.append("Function: " + context.at(2) + "\n");
str.append("Line: " + context.at(3) + "\n");
str.append("Version: " + context.at(4));
str.append("\n*** Information Complete ***\n");
write(str);
break;
case QtWarningMsg:
if(!(context.at(2).contains("setGeometry")))
{
str.append("\n*** Warning ***\n");
...
str.append("\n*** Warning Complete ***\n");
write(str);
errorMsg = true;
emit Logger::ptr->SaveSession();
}
break;
case QtCriticalMsg:
str.append("\n*** Critical ***\n");
...
str.append("\n*** Critical Complete ***\n");
write(str);
errorMsg = true;
emit Logger::ptr->SaveSession();
break;
case QtFatalMsg:
str.append("\n*** Fatal ***\n");
...
str.append("\n*** Fatal Complete ***\n");
write(str);
errorMsg = false;
emit Logger::ptr->FatalSaveSession();
QApplication::exit(-2);
}
Logger::mutex->unlock();
}
void Logger::write(QString str)
{
if(!stream)
return;
if(str.isEmpty())
return;
(*stream) << str; //!!!!!!!!!!!!CRASHES HERE***********
stream->flush();
}
void Logger::moveLogToSession(QString sessionName)
{
QMutex *myMutex = get_obj()->mutex;
myMutex->lock();
QTextStream *myStream = get_obj()->stream;
myStream->flush();
QFile *myLogFile = get_obj()->logFile;
myLogFile->flush();
myLogFile->close();
delete myStream;
QString path = SystemVariables::getAppData() + "/Smovault/Logs";
if(!myLogFile->open(QFile::ReadOnly | QFile::Text))
{
QString errtitle = "FATAL ERROR!";
QString errtxt = myLogFile->errorString() + "\nCould not open the log file: ";
errtxt.append(path + "/Session.log");
errtxt.append(".\nApplication Abort!");
QMessageBox *mb = new QMessageBox(QMessageBox::Critical, errtitle, errtxt);
mb->exec();
delete mb;
QApplication::exit(-1);
}
QTextStream in(myLogFile);
QString data = in.readAll();
myLogFile->close();
myLogFile->remove();
delete myLogFile;
path = SystemVariables::getAppData() + "/Smovault/Sessions/" + sessionName;
myLogFile = new QFile(path + "/Session.log");
if(!myLogFile->open(QFile::WriteOnly | QFile::Text))
{
QString errtitle = "FATAL ERROR!";
QString errtxt = myLogFile->errorString() + "\nCould not write to the log file: ";
errtxt.append(path + "/Session.log");
errtxt.append(".\nApplication Abort!");
QMessageBox *mb = new QMessageBox(QMessageBox::Critical, errtitle, errtxt);
mb->exec();
delete mb;
QApplication::exit(-1);
}
QTextStream out(myLogFile);
out << data;
out.flush();
myLogFile->flush();
myStream = new QTextStream(myLogFile);
myStream->setRealNumberNotation(QTextStream::SmartNotation);
myStream->setRealNumberPrecision(15);
myMutex->unlock();
}
I would really be thankful if someone could help me by pointing out my mistakes.

If crash happens after calling moveLogToSession, i guess that happens because you destroy stream
QTextStream *myStream = get_obj()->stream;
myStream->flush();
...
delete myStream; // here
And never setting up the new stream
myStream = new QTextStream(myLogFile);
get_obj()->stream = myStream; // you need THIS

Related

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.

QAbstractNativeEventFilter not receive XCB_KEY_PRESS

I'm building a Qt application that process native xcb events. But cannot receive key press event or mouse events.
Below are my codes.
// myfilter.h
class MyFilter : public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT
public:
explicit MyFilter(xcb_connection_t *conn, QObject *parent = nullptr);
~MyFilter();
virtual bool nativeEventFilter(const QByteArray &eventType, void *message,
long *result) override;
signals:
private:
xcb_connection_t *_conn;
xcb_window_t _rootWindow;
};
// myfilter.cpp
MyFilter::MyFilter(xcb_connection_t *conn, QObject *parent)
: QObject(parent)
{
this->_conn = conn;
xcb_screen_t *screen;
screen = xcb_setup_roots_iterator(xcb_get_setup(this->_conn)).data;
this->_rootWindow = screen->root;
qDebug() << "Root window: " << this->_rootWindow;
// xcb_grab_key(this->_conn, 1, screen->root, XCB_MOD_MASK_ANY, XCB_GRAB_ANY,
// XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
QCoreApplication::instance()->installNativeEventFilter(this);
}
MyFilter::~MyFilter()
{
xcb_disconnect(this->_conn);
}
bool MyFilter::nativeEventFilter(const QByteArray &eventType,
void *message, long *result)
{
if (eventType == "xcb_generic_event_t") {
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t*>(message);
auto responseType = ev->response_type & ~0x80;
switch (responseType) {
case XCB_KEY_PRESS:
qDebug() << "XCB_KEY_PRESS";
break;
case XCB_EXPOSE:
qDebug() << "XCB_EXPOSE";
break;
case XCB_PROPERTY_NOTIFY:
{
xcb_property_notify_event_t *property_notify = (xcb_property_notify_event_t*)ev;
qDebug() << "XCB_PROPERTY_NOTIFY" << property_notify->atom << property_notify->window;
break;
}
case XCB_CLIENT_MESSAGE:
{
xcb_client_message_event_t *client_message = (xcb_client_message_event_t*)ev;
qDebug() << "XCB_CLIENT_MESSAGE" << client_message->window;
break;
}
default:
qDebug() << responseType;
break;
}
} else {
qDebug() << "Not a xcb_generic_event_t";
}
return false;
}
and
// main.cpp
#include <QApplication>
#include <QX11Info>
#include <xcb/xcb.h>
#include "myfilter.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
xcb_connection_t *conn = QX11Info::connection();
MyFilter myFilter(conn);
return a.exec();
}
I want to receive XCB_KEY_PRESS but when I run this application and press any key, it always prints 85 which is defined as XCB_ALLOC_NAMED_COLOR.
What is this event and why response_type reports this rather than XCB_KEY_PRESS?

Qt Program freeze when try to get MD5 of files

Hi im using this code for generate MD5 of files in QT
QString Md5_gen(QString const &s)
{
QString pakchunk_Md5;
QCryptographicHash crypto(QCryptographicHash::Md5);
QFile pakchunk("D:/Games/TDPA - Man of Medan" + s);
if (pakchunk.open(QIODevice::ReadOnly))
{
while(!pakchunk.atEnd()){
crypto.addData(pakchunk.read(8192));
}
} else
{
qDebug() << "Can't open file.";
pakchunk_Md5 = "nofile";
return pakchunk_Md5;
}
pakchunk_Md5 = crypto.result().toHex();
return pakchunk_Md5;
}
I need to Generate MD5 of 8 Big file with this code (1.5GB>) Problem is When i press button to start Generate MD5, GUI Freeze until all MD5 generated
Im Test QFuture, QFutureWatcher, QtConcurrent in this way, But no luck GUi still freeze every time
main.cpp
#include "user_def.h"
#include "mainwindow2.h"
#include...
QString Md5_gen(QString const &s)
{
QString pakchunk_Md5;
QCryptographicHash crypto(QCryptographicHash::Md5);
QFile pakchunk("D:/Games/TDPA - Man of Medan" + s);
if (pakchunk.open(QIODevice::ReadOnly))
{
while(!pakchunk.atEnd()){
crypto.addData(pakchunk.read(8192));
}
} else
{
qDebug() << "Can't open file.";
pakchunk_Md5 = "nofile";
return pakchunk_Md5;
}
pakchunk_Md5 = crypto.result().toHex();
return pakchunk_Md5;
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
a.setStyle(new DarkStyle);
FramelessWindow framelessWindow;
framelessWindow.setWindowIcon(a.style()->standardIcon(QStyle::SP_DesktopIcon));
MainWindow *mainWindow = new MainWindow;
framelessWindow.setContent(mainWindow);
framelessWindow.show();
return a.exec();
}
user_def.h
#ifndef USER_DEF_H
#define USER_DEF_H
#include <QString>
QString Md5_gen(QString const &s);
#endif // USER_DEF_H
mainwindow2.h
#ifndef MAINWINDOW2_H
#define MAINWINDOW2_H
#include <QMainWindow>
#include <QtConcurrentRun>
#include <QFuture>
#include <QFutureWatcher>
#include <QThread>
#include <QThreadPool>
#include "user_def.h"
namespace Ui {
class MainWindow2;
}
class MainWindow2 : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow2(QWidget *parent = nullptr);
~MainWindow2();
public slots:
void run_thread();
void displayFinishedBox();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow2 *ui;
QFutureWatcher<QString> *watcher;
QFuture<QString> *future;
};
#endif // MAINWINDOW2_H
mainwindow2.cpp
#include...
MainWindow2::MainWindow2(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow2)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked,
this, &MainWindow2::run_thread);
// display a message box when the calculation has finished
future = new QFuture<QString>;
watcher = new QFutureWatcher<QString>;
connect(watcher, SIGNAL(finished()),
this, SLOT(displayFinishedBox()));
}
MainWindow2::~MainWindow2()
{
delete ui;
}
void MainWindow2::run_thread()
{
int file_ok = 0;
//file pak33
QString loc33 = "/SM/test1.pak";
QFuture<QString> future33 = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc33);
watcher->setFuture(future33);
QString pakchunk33 = future33.result();
qDebug() << pakchunk33;
if (pakchunk33 == "f7002d4419cd235a87746715ba6fb2ea")
{
qDebug() << "OK";
file_ok++;
ui->label_8->setText("OK");
ui->label_8->setStyleSheet("QLabel { color : green; }");
} else if (pakchunk33 == "nofile")
{
qDebug() << "no file found";
ui->label_8->setText("not found");
ui->label_8->setStyleSheet("QLabel { color : red; }");
} else
{
qDebug() << "file is diffrent";
ui->label_8->setText("wrong");
ui->label_8->setStyleSheet("QLabel { color : red; }");
}
ui->progressBar->setValue(12);
//file pak34
QString loc34 = "/SM/test2.pak";
QFuture<QString> future34 = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc34);
watcher->setFuture(future34);
QString pakchunk34 = future34.result();
qDebug() << pakchunk34;
if (pakchunk34 == "64c77598586b6c3cb60beed0b0750620")
{
qDebug() << "OK";
file_ok++;
ui->label->setText("OK");
ui->label->setStyleSheet("QLabel { color : green; }");
} else if (pakchunk34 == "nofile")
{
qDebug() << "no file found";
ui->label->setText("not found");
ui->label->setStyleSheet("QLabel { color : red; }");
} else
{
qDebug() << "file is diffrent";
ui->label->setText("wrong");
ui->label->setStyleSheet("QLabel { color : red; }");
}
ui->progressBar->setValue(25);
//file pak35
QString loc35 = "/SM/test3.pak";
QFuture<QString> future35 = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc35);
watcher->setFuture(future35);
QString pakchunk35 = future35.result();
qDebug() << pakchunk35;
if (pakchunk35 == "ee53f7a7656a32b5278c460baec46f16")
{
qDebug() << "OK";
file_ok++;
ui->label_7->setText("OK");
ui->label_7->setStyleSheet("QLabel { color : green; }");
} else if (pakchunk35 == "nofile")
{
qDebug() << "no file found";
ui->label_7->setText("not found");
ui->label_7->setStyleSheet("QLabel { color : red; }");
} else
{
qDebug() << "file is diffrent";
ui->label_7->setText("wrong");
ui->label_7->setStyleSheet("QLabel { color : red; }");
}
ui->progressBar->setValue(38);
/*Some other code*/
can anybody say what is my problem and how can i fix it?
edit 1
I edit my code in this way
it working good without freeze gui
in term of coding this code is standard?
mainwindow2.cpp
MainWindow2::MainWindow2(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow2)
{
ui->setupUi(this);
connect(ui->pushButton_3, &QPushButton::clicked, this, &MainWindow2::MD5_thread_1);
future = new QFuture<QString>;
watcher1 = new QFutureWatcher<QString>;
watcher2 = new QFutureWatcher<QString>;
watcher3 = new QFutureWatcher<QString>;
connect(watcher1, &QFutureWatcher<QString>::finished, this, &MainWindow2::MD5_thread_2);
connect(watcher2, &QFutureWatcher<QString>::finished, this, &MainWindow2::MD5_thread_3);
connect(watcher3, &QFutureWatcher<QString>::finished, this, &MainWindow2::MD5_thread_4);
//some other code
}
void MainWindow2::MD5_thread_1()
{
ui->pushButton->setEnabled(false);
ui->pushButton->setText("procces started");
ui->pushButton->setStyleSheet("QPushButton { color : white; background-color: rgb(73, 80, 93); }");
ui->label->setText("checking");
ui->label_2->setText("checking");
ui->label_3->setText("checking");
ui->label_4->setText("checking");
ui->label_5->setText("checking");
ui->label_6->setText("checking");
ui->label_7->setText("checking");
ui->label_8->setText("checking");
ui->label_14->setText("waiting for end of check");
ui->progressBar->setRange(0, 100);
ui->progressBar_2->setRange(0, 100);
ui->progressBar->setValue(0);
ui->progressBar_2->setValue(0);
//file pak33
QString loc33 = "/SMG0/editor.pak";
*future= QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc33);
watcher1->setFuture(*future);
}
void MainWindow2::MD5_thread_2()
{
QString pakchunk33 = future->result();
qDebug() << pakchunk33;
if (pakchunk33 == "f7002d4419cd235a87746715ba6fb2ea")
{
qDebug() << "OK";
file_ok++;
ui->label_8->setText("OK");
ui->label_8->setStyleSheet("QLabel { color : green; }");
} else if (pakchunk33 == "nofile")
{
qDebug() << "no file found";
ui->label_8->setText("not found");
ui->label_8->setStyleSheet("QLabel { color : red; }");
} else
{
qDebug() << "file is diffrent";
ui->label_8->setText("wrong");
ui->label_8->setStyleSheet("QLabel { color : red; }");
}
ui->progressBar->setValue(12);
watcher1->deleteLater();
//file pak34
QString loc34 = "/SMG0/2Editor.pak";
*future = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc34);
watcher2->setFuture(*future);
}
void MainWindow2::MD5_thread_3()
{
QString pakchunk34 = future->result();
qDebug() << pakchunk34;
if (pakchunk34 == "64c77598586b6c3cb60beed0b0750620")
{
qDebug() << "OK";
file_ok++;
ui->label->setText("OK");
ui->label->setStyleSheet("QLabel { color : green; }");
} else if (pakchunk34 == "nofile")
{
qDebug() << "no file found";
ui->label->setText("not found");
ui->label->setStyleSheet("QLabel { color : red; }");
} else
{
qDebug() << "file is diffrent";
ui->label->setText("wrong");
ui->label->setStyleSheet("QLabel { color : red; }");
}
ui->progressBar->setValue(25);
watcher2->deleteLater();
//file pak35
QString loc35 = "/SMG0/3Editor.pak";
*future = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc35);
watcher3->setFuture(*future);
}
void MainWindow2::core_install
{
QString pakchunk35 = future->result();
qDebug() << pakchunk40;
if (pakchunk40 == "49e0440340044f424caeb82bade1301f")
{
qDebug() << "OK";
file_ok++;
ui->label_2->setText("OK");
ui->label_2->setStyleSheet("QLabel { color : green; }");
} else if (pakchunk40 == "nofile")
{
qDebug() << "no file found";
ui->label_2->setText("not found");
ui->label_2->setStyleSheet("QLabel { color : red; }");
} else
{
qDebug() << "file is diffrent";
ui->label_2->setText("wrong");
ui->label_2->setStyleSheet("QLabel { color : red; }");
}
ui->progressBar->setValue(100);
watcher3->deleteLater();
//check if game is okey or not
if (file_ok == 8)
{
ui->label_14->setText("O");
ui->label_14->setStyleSheet("QLabel { color : green; }");
} else
{
ui->label_14->setText("X");
ui->label_14->setStyleSheet("QLabel { color : red; }");
}
}
mainwindow2.h
#ifndef MAINWINDOW2_H
#define MAINWINDOW2_H
#include <QMainWindow>
#include <QtConcurrentRun>
#include <QFuture>
#include <QFutureWatcher>
#include <QThread>
#include <QThreadPool>
#include "user_def.h"
namespace Ui {
class MainWindow2;
}
class MainWindow2 : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow2(QWidget *parent = nullptr);
~MainWindow2();
public slots:
void MD5_thread_1();
void MD5_thread_2();
void MD5_thread_3();
void core_install();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_radioButton_2_clicked();
void on_radioButton_4_clicked();
void on_radioButton_3_clicked();
void on_radioButton_clicked();
private:
Ui::MainWindow2 *ui;
QFutureWatcher<QString> *watcher1;
QFutureWatcher<QString> *watcher2;
QFutureWatcher<QString> *watcher3;
QFuture<QString> *future;
int file_ok = 0;
};
#endif // MAINWINDOW2_H
The result method blocks your UI thread, making the whole concurrent / future dance useless.
Create a watcher per future and link its finished signal to a lambda that passes both the filename and the contents of the result to a onHashCalculated method on your window. In that method you can check if the hash matches one of your predefined hashes, and update the UI.
Alternatively, move your current run_thread function to a separate QObject that runs on a separate thread, and have it emit a hashCalculated(name, hash) signal that your mainwindow subscribes to using a onHashCalculated slot similar to the one I described above.
Here is code for a HashChecker that encapsulates both approaches.
Note the static QMap that maps filenames to hashes, the way doneFile is chained to checkDone.
enum class Status { Ok, NotOk, Missing };
class HashChecker : public QObject {
Q_OBJECT
public:
QMap<QString, Status> done;
HashChecker(QObject *parent = nullptr) : QObject(parent) {
QObject::connect(this, &HashChecker::doneFile, this, &HashChecker::checkDone);
}
inline static const QMap<QString, QString> hashes = {
{"/SM/test1.pak", "f7002d4419cd235a87746715ba6fb2ea"},
{"/SM/test2.pak", "64c77598586b6c3cb60beed0b0750620"},
{"/SM/test3.pak", "ee53f7a7656a32b5278c460baec46f16"},
};
signals:
void finished();
void doneFile(const QString& fname, Status s);
private slots:
void checkDone(const QString& fname, Status s) {
done[fname] = s;
if (done.size() == hashes.size())
emit finished();
}
public slots:
void check_parallel() {
for (auto it = hashes.cbegin(); it != hashes.cend(); it++) {
auto fname = it.key();
auto hash = it.value();
QFuture<Status> fut = QtConcurrent::run(do_hash, fname, hash);
QFutureWatcher<Status> *fw = new QFutureWatcher<Status>(this);
fw->setFuture(fut);
QObject::connect(fw, &QFutureWatcher<Status>::finished, this,
[=]() {
fw->deleteLater();
emit doneFile(fname, fut.result());
});
}
}
void check_sequential() {
for (auto it = hashes.cbegin(); it != hashes.cend(); it++) {
auto fname = it.key();
auto hash = it.value();
auto result = do_hash(fname, hash);
emit doneFile(fname, result);
}
}
};
If you want to check files in parallel:
HashChecker *hc = new HashChecker();
QObject::connect(hc, &HashChecker::doneFile, this, &MainWindow2::onHashCalculated);
hc->check_parallel();
Sequential in a different thread is almost the same:
QThread *t = new QThread(this);
HashChecker *hc = new HashChecker();
hc->moveToThread(t);
QObject::connect(t, &QThread::started, hc, &HashChecker::check_sequential);
QObject::connect(hc, &HashChecker::doneFile, this, &MainWindow2::onHashCalculated);
QObject::connect(hc, &HashChecker::finished, t, &QThread::quit);
t->start();

QT Downloading File with QNetworkAccessManager

I am trying to make the code in this question work.
qt - how to download and save image via http?
It creates the files, but no data is written to them.
My best guess is that the connect to the singals and slots is not working.
What am I doing wrong?
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
QString getPageImage(QString url = "");
bool saveToDisk(const QString &filename, QIODevice *data);
~MainWindow();
private slots:
void on_btnDownload_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
qdownload.h
#ifndef QDOWNLOADER_H
#define QDOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <QStringList>
#include <QDir>
#include <QDebug>
class QDownloader : public QObject
{
Q_OBJECT
public:
explicit QDownloader(QObject *parent = 0);
virtual ~QDownloader();
void setFile(QString fileURL, QString folderName, QString fileName);
private:
QNetworkAccessManager *manager;
QNetworkReply *reply;
QFile *file;
private slots:
void onDownloadProgress(qint64,qint64);
void onFinished(QNetworkReply*);
void onReadyRead();
void onReplyFinished();
};
#endif // QDOWNLOADER_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QNetworkAccessManager"
#include "QNetworkReply"
#include "QFile"
#include "QDebug"
#include "QUrl"
#include "QStringList"
#include "qdownloader.h"
#include <QTimer>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->progressBar->setVisible(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnDownload_clicked()
{
QString link = ui->txtURL->text();
int issue = ui->sbIssue->value();
ui->progressBar->setMaximum(issue);
ui->progressBar->setValue(0);
ui->progressBar->setVisible(true);
for(int j = 1; j <= issue; j++){
int i = 1;
while(getPageImage(link + "/" + QString::number(j) + "/" + QString::number(i) + "/").length() > 0){
QString filename = "http://" + getPageImage(link + "/" + QString::number(j) + "/" + QString::number(i) + "/");
qDebug() << filename;
QDownloader qDL;
qDL.setFile(filename,ui->txtTitle->text() + "_" + QString::number(j),ui->txtTitle->text() + "_" + QString::number(j) + "_" + QString::number(i));
//qDebug() << getPageImage(link + "/" + QString::number(j) + "/" + QString::number(i) + "/").length();
i++;
}
ui->progressBar->setValue(j);
}
ui->progressBar->setVisible(false);
}
QString MainWindow::getPageImage(QString url){
QString pic = "";
if(url.length() > 0){
QNetworkAccessManager manager;
QNetworkReply *response = manager.get(QNetworkRequest(QUrl(url)));
QEventLoop event;
connect(response,SIGNAL(finished()),&event,SLOT(quit()));
event.exec();
QString html = response->readAll();
if(html.length() > 0){
QStringList str;
str = html.split("\n");
//qDebug() << url;
for (int i = 0; i < str.size(); ++i){
if(str.at(i).contains("id=\"mainImg\"", Qt::CaseInsensitive)){
pic = str.at(i);
pic = pic.remove(QRegExp("<img[^>]*src=['|\"]", Qt::CaseInsensitive));
pic = pic.remove(QString::fromStdString("//"), Qt::CaseInsensitive);
pic = pic.remove('"');
pic = pic.remove("'");
pic = pic.remove('<');
pic = pic.remove('>');
pic = pic.remove(';');
pic = pic.left(pic.length()-1);
//qDebug() << str.at(i);
//qDebug() << pic;
}
}
}else{
pic = "";
}
//qDebug() << "Lines: " << str.size();
}else{
pic = "";
}
return pic;
}
qdownload.cpp
#include "qdownloader.h"
QDownloader::QDownloader(QObject *parent) :
QObject(parent)
{
manager = new QNetworkAccessManager;
}
QDownloader::~QDownloader()
{
manager->deleteLater();
}
void QDownloader::setFile(QString fileURL, QString folderName, QString fileName)
{
QDir dir;
if(dir.exists(folderName)){
//qDebug() << "Existis: " + folderName;
}else{
dir.mkdir(folderName);
//() << "Created: " + folderName;
}
QString filePath = fileURL;
QStringList filePathList = filePath.split('/');
QString fileExt = filePathList.at(filePathList.count() - 1);
fileExt = "jpg";
QString saveFilePath;
saveFilePath = QString(folderName + "/" + fileName + "." + fileExt );
QNetworkRequest request;
request.setUrl(QUrl(fileURL));
reply = manager->get(request);
file = new QFile;
file->setFileName(saveFilePath);
connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(onDownloadProgress(qint64,qint64)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onFinished(QNetworkReply*)));
connect(reply,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
connect(reply,SIGNAL(finished()),this,SLOT(onReplyFinished()));
}
void QDownloader::onDownloadProgress(qint64 bytesRead,qint64 bytesTotal)
{
qDebug(QString::number(bytesRead).toLatin1() +" - "+ QString::number(bytesTotal).toLatin1());
}
void QDownloader::onFinished(QNetworkReply * reply)
{
switch(reply->error())
{
case QNetworkReply::NoError:
{
qDebug("file is downloaded successfully.");
}break;
default:{
qDebug(reply->errorString().toLatin1());
};
}
if(file->isOpen())
{
file->close();
file->deleteLater();
}
}
void QDownloader::onReadyRead()
{
qDebug() << "Ready";
file->open(QIODevice::WriteOnly);
file->write(reply->readAll());
}
void QDownloader::onReplyFinished()
{
if(file->isOpen())
{
file->close();
file->deleteLater();
}
}
I prepared a very basic example you can use as reference.
In some place in "my" downloader I launch the request:
QNetworkRequest request;
request.setUrl(org);
_reply = _manager->get(request); // Manager is my QNetworkAccessManager
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
connect(_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateProgress(qint64, qint64)));
connect(_reply, SIGNAL(finished()),
this, SLOT(finished()));
As you can see all you need to do is to get() and properly use the signals of the QNetworkReply.
Following "my" slots:
void MyDownloader::error(QNetworkReply::NetworkError err)
{
// Manage error here.
_reply->deleteLater();
}
void MyDownloader::updateProgress(qint64 read, qint64 total)
{
// This is where you can use the progress info for, lets say, update a progress bar:
// progressBar->setMaximum(total);
// progressBar->setValue(read);
}
void MyDownloader::finished()
{
// Save the image here
QByteArray b = _reply->readAll();
QFile file(des); // "des" is the file path to the destination file
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << b;
_reply->deleteLater();
// done
}
Notice that you can write to the file in updateProgress() instead of writing the whole file at once when the reply is finished.
For writing on updateProgress(), open and/or create the QFile at get time. Then use reply's readAll on every update and write the read data to the file then close the file when finished.
// ...
_file = new QFile(des);
_reply = _manager->get(request);
/// ...
void MyDownloader::updateProgress(qint64 read, qint64 total)
{
QByteArray b = _reply->readAll();
QDataStream out(_file);
out << b;
}
void MyDownloader::finished()
{
// Done
_reply->deleteLater();
_file->close();
// probably delete the file object too
}

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.