Qt Program freeze when try to get MD5 of files - c++

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();

Related

How to visualize a .txt or .csv file on a QTableView after triggering currentRowChanged(int currentRow) on QListWidget?

Problem: How to visualize a .txt or .csv file on a QTableView after triggering currentRowChanged(int currentRow) on QListWidget?
I have a very simple interface that I designed as a minimal verifiable example that look like below with a QPushButton a QLineEdit a QListWidget and a QTableView.
If I upload a .csv file using the QPushButton there are no problem and the content of the file is correctly shown on a QTableView:
However, and here is the problem:
When I drag and drop (functionality correctly implemented) multiple files and I click on one of them I have problem visualizing the file because the content does not change. It seems that the slot currentRowChanged(int currentRow) in the QListWidget is never triggered despite the files exists.
Below is the desired result:
Here is the example I implemented. If you copy/paste on your computer it will work no problem:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidgetItem>
#include <QStandardItemModel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
enum fileFormat {
CSV,
TXT,
OTHER
};
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void showFilesDetails(QListWidgetItem *item);
void readFile(QString path, fileFormat format);
void setValueAt(int ix, int jx, const QString &value);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private slots:
void on_listWidget_currentRowChanged(int currentRow);
void on_loadBtn_clicked();
private:
Ui::MainWindow *ui;
fileFormat *format;
QStandardItemModel *model;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDragEnterEvent>
#include <QDragLeaveEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QDebug>
#include <QFileDialog>
namespace constants
{
const QStringList HEADERS = {
"tax_id", "Org_name", "GeneID", "CurrentID", "Status"};
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setAcceptDrops(true);
model = new QStandardItemModel(this);
ui->tableView->setModel(model);
model->setHorizontalHeaderLabels(constants::HEADERS);
model->setColumnCount(constants::HEADERS.length());
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
QHeaderView *horizontal = new QHeaderView(Qt::Horizontal, ui->tableView);
horizontal->setSectionsClickable(true);
horizontal->setHighlightSections(true);
ui->tableView->setHorizontalHeader(horizontal);
}
MainWindow::~MainWindow(){ delete ui; }
void MainWindow::dragEnterEvent(QDragEnterEvent *event) { event->accept(); }
void MainWindow::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); }
void MainWindow::dragMoveEvent(QDragMoveEvent *event) { event->accept(); }
void MainWindow::dropEvent(QDropEvent *event)
{
QString name;
QList<QUrl> urls;
QList<QUrl>::Iterator i;
urls = event->mimeData()->urls();
for(i = urls.begin(); i != urls.end(); ++i) {
name = i->path();
ui->listWidget->addItem(name);
}
}
void MainWindow::on_listWidget_currentRowChanged(int currentRow)
{
QListWidgetItem *item = nullptr;
if(ui->listWidget->count() > 0)
ui->listWidget->setCurrentRow(currentRow);
showFilesDetails(item);
}
void MainWindow::readFile(QString path, fileFormat format)
{
QListWidgetItem *item = nullptr;
QFile file(path);
if(!file.exists()){
qDebug() << "File does not exist "<<path;
}else{
qDebug() << path<< "File exist...";
}
if (file.fileName().endsWith(".txt", Qt::CaseInsensitive))
{
qDebug() << "File does not exist "<<file.fileName();
} else if(file.fileName().endsWith(".csv", Qt::CaseInsensitive))
{
qDebug() << "File does not exist "<<file.fileName();
}
QString line;
if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
QTextStream stream(&file);
while (!stream.atEnd()){
line = stream.readLine();
ui->listWidget->setCurrentItem(item);
qDebug() << "line: "<<line;
}
}
file.close();
}
void MainWindow::showFilesDetails(QListWidgetItem *item)
{
QString path;
fileFormat frmt;
readFile(path, frmt);
ui->listWidget->setCurrentItem(item);
}
void MainWindow::on_loadBtn_clicked()
{
auto filename = QFileDialog::getOpenFileName(this, "Open", QDir::rootPath(), "CSV file (*.csv)");
if(filename.isEmpty()) {
ui->statusbar->showMessage("File empty");
return;
}
QFile file(filename);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
ui->statusbar->showMessage("File did not open");
return;
}
QTextStream xin(&file);
int ix = 0;
while (!xin.atEnd()) {
model->setRowCount(ix);
auto line = xin.readLine();
auto values = line.split(",");
const int colCount = values.size();
model->setColumnCount(colCount);
for(int jx = 0; jx < colCount; ++jx) {
setValueAt(ix, jx, values.at(jx));
}
++ix;
ui->lineEdit->setText(filename);
ui->statusbar->showMessage(filename);
}
ui->listWidget->addItem(filename);
file.close();
}
void MainWindow::setValueAt(int ix, int jx, const QString &value)
{
if (!model->item(ix, jx)) {
model->setItem(ix, jx, new QStandardItem(value));
} else {
model->item(ix, jx)->setText(value);
}
}
In order to solve the problem I read very useful sources and in particular I came across this one, this one and also I found this post useful. However, I am trying to figure out where the problem might be.
The drag/drop functionality is properly implemented but how do I upload the files in the QTableView and properly trigger the QListWidget event?
Thank to anyone who would have time to read and point to a potential solution.
afaik,funtion on_listWidget_currentRowChanged triggered properly.
function showFilesDetails passes an empty string to readFile,this may be the problem.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDragEnterEvent>
#include <QDragLeaveEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QDebug>
#include <QFileDialog>
namespace constants
{
const QStringList HEADERS = {
"tax_id", "Org_name", "GeneID", "CurrentID", "Status"};
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setAcceptDrops(true);
model = new QStandardItemModel(this);
ui->tableView->setModel(model);
model->setHorizontalHeaderLabels(constants::HEADERS);
model->setColumnCount(constants::HEADERS.length());
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
QHeaderView *horizontal = new QHeaderView(Qt::Horizontal, ui->tableView);
horizontal->setSectionsClickable(true);
horizontal->setHighlightSections(true);
ui->tableView->setHorizontalHeader(horizontal);
}
MainWindow::~MainWindow(){ delete ui; }
void MainWindow::dragEnterEvent(QDragEnterEvent *event) { event->accept(); }
void MainWindow::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); }
void MainWindow::dragMoveEvent(QDragMoveEvent *event) { event->accept(); }
void MainWindow::dropEvent(QDropEvent *event)
{
QString name;
QList<QUrl> urls;
QList<QUrl>::Iterator i;
urls = event->mimeData()->urls();
for(i = urls.begin(); i != urls.end(); ++i) {
name = i->toLocalFile();
ui->listWidget->addItem(name);
}
}
void MainWindow::on_listWidget_currentRowChanged(int currentRow)
{
QListWidgetItem *item = nullptr;
if(ui->listWidget->count() > 0)
ui->listWidget->setCurrentRow(currentRow);
showFilesDetails(item);
}
void MainWindow::readFile(QString path, fileFormat format)
{
QListWidgetItem *item = nullptr;
QFile file(path);
if(!file.exists()){
qDebug() << "File does not exist "<<path;
}else{
qDebug() << path<< "File exist...";
}
if (file.fileName().endsWith(".txt", Qt::CaseInsensitive))
{
qDebug() << "File does not exist "<<file.fileName();
} else if(file.fileName().endsWith(".csv", Qt::CaseInsensitive))
{
qDebug() << "File does not exist "<<file.fileName();
}file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream xin(&file);
int ix = 0;
while (!xin.atEnd()) {
model->setRowCount(ix);
auto line = xin.readLine();
auto values = line.split(",");
const int colCount = values.size();
model->setColumnCount(colCount);
for(int jx = 0; jx < colCount; ++jx) {
setValueAt(ix, jx, values.at(jx));
}
++ix;
ui->lineEdit->setText(path);
ui->statusbar->showMessage(path);
}
file.close();
}
void MainWindow::showFilesDetails(QListWidgetItem *item)
{
item=ui->listWidget->currentItem();
QString path=
item->data(Qt::DisplayRole).toString();;
fileFormat frmt;
readFile(path, frmt);
ui->listWidget->setCurrentItem(item);
}
void MainWindow::on_loadBtn_clicked()
{
auto filename = QFileDialog::getOpenFileName(this, "Open", QDir::rootPath(), "CSV file (*.csv)");
if(filename.isEmpty()) {
ui->statusbar->showMessage("File empty");
return;
}
QFile file(filename);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
ui->statusbar->showMessage("File did not open");
return;
}
QTextStream xin(&file);
int ix = 0;
while (!xin.atEnd()) {
model->setRowCount(ix);
auto line = xin.readLine();
auto values = line.split(",");
const int colCount = values.size();
model->setColumnCount(colCount);
for(int jx = 0; jx < colCount; ++jx) {
setValueAt(ix, jx, values.at(jx));
}
++ix;
ui->lineEdit->setText(filename);
ui->statusbar->showMessage(filename);
}
ui->listWidget->addItem(filename);
file.close();
}
void MainWindow::setValueAt(int ix, int jx, const QString &value)
{
if (!model->item(ix, jx)) {
model->setItem(ix, jx, new QStandardItem(value));
} else {
model->item(ix, jx)->setText(value);
}
}

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
}

Adding Text in GraphicsView in Qt

I am implementing a code to add different entities on a button click.I am getting a problem to add Text in graphics view. Following is the code snippet that I am implementing. What needs to be done?
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPaintEvent>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPainter>
#include "line.h"
#include "circle.h"
#include "ellipse.h"
#include "point.h"
#include "arc.h"
#include "text.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void wheelEvent(QWheelEvent* event);
private:
Ui::MainWindow *ui;
bool mFirstClick;
bool mPaintFlag;
int mStartX;
int mStartY;
int mEndX;
int mEndY;
QGraphicsScene *scene;
QPainter *painter;
point *item;
line *item1;
circle *item2;
ellipse *item3;
arc *item4;
private slots:
void drawPoint();
void drawLine();
void drawCircle();
void drawEllipse();
void drawArc();
void drawText();
void on_actionSave_triggered();
void on_actionOpen_triggered();
void on_actionQuit_2_triggered();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMouseEvent>
#include<QFileDialog>
#include<QMessageBox>
#include<QTextEdit>
#include<QString>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(tr("GD CAD"));
scene = new QGraphicsScene;
for(int x = 0; x <= ui->graphicsView->width(); x += 10){
scene->addLine(x,0,x,ui->graphicsView->height(),QPen(Qt::green));
}
for(int y = 0; y <= ui->graphicsView->height(); y += 10){
scene->addLine(0,y,ui->graphicsView->width(),y,QPen(Qt::green));
}
for(int x = 10; x <= ui->graphicsView->width(); x += 100){
scene->addLine(x,0,x,ui->graphicsView->height(),QPen(Qt::darkGreen));
}
for(int y = 10; y <= ui->graphicsView->height(); y += 100){
scene->addLine(0,y,ui->graphicsView->width(),y,QPen(Qt::darkGreen));
}
ui->graphicsView->setScene(scene);
connect(ui->pointButton, SIGNAL(clicked()), this, SLOT(drawPoint()));
connect(ui->lineButton, SIGNAL(clicked()), this, SLOT(drawLine()));
connect(ui->circleButton, SIGNAL(clicked()), this, SLOT(drawCircle()));
connect(ui->ellipseButton, SIGNAL(clicked()), this, SLOT(drawEllipse()));
connect(ui->arcButton, SIGNAL(clicked()),this, SLOT(drawArc()));
connect(ui->text,SIGNAL(clicked()),this,SLOT(drawText()));
connect(ui->actionPoints, SIGNAL(triggered()), this, SLOT(drawPoint()));
connect(ui->actionLine, SIGNAL(triggered()), this, SLOT(drawLine()));
connect(ui->actionCircle, SIGNAL(triggered()), this, SLOT(drawCircle()));
connect(ui->actionEllipse, SIGNAL(triggered()), this, SLOT(drawEllipse()));
}
void MainWindow::drawPoint(){
ui->graphicsView->setScene(scene);
item = new point;
scene->addItem(item);
qDebug() << "Point Created";
connect(item, SIGNAL(DrawFinished()), this, SLOT(drawPoint()));
}
void MainWindow::drawLine(){
ui->graphicsView->setScene(scene);
item1 = new line;
scene->addItem(item1);
qDebug() << "Line Created";
connect(item1, SIGNAL(DrawFinished()), this, SLOT(drawLine()));
}
void MainWindow::drawCircle(){
ui->graphicsView->setScene(scene);
item2 = new circle;
scene->addItem(item2);
qDebug() << "Circle Created";
connect(item2, SIGNAL(DrawFinished()), this, SLOT(drawCircle()));
}
void MainWindow::drawArc(){
ui->graphicsView->setScene(scene);
item4 = new arc;
scene->addItem(item4);
qDebug() << "Circle Created";
connect(item4, SIGNAL(DrawFinished()), this, SLOT(drawArc()));
}
void MainWindow::drawEllipse(){
ui->graphicsView->setScene(scene);
item3 = new ellipse;
scene->addItem(item3);
qDebug() << "Ellipse Created";
connect(item3, SIGNAL(DrawFinished()), this, SLOT(drawEllipse()));
}
void MainWindow::wheelEvent(QWheelEvent* event) {
ui->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
// Scale the view / do the zoom
double scaleFactor = 1.15;
if(event->delta() > 0) {
// Zoom in
ui->graphicsView->scale(scaleFactor, scaleFactor);
} else {
// Zooming out
ui->graphicsView->scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
}
void MainWindow::on_actionOpen_triggered()
{
QString filename=QFileDialog::getOpenFileName(
this,
tr("Open File"),
QString(),
tr("file Name(*.dwg|*.DWG|*.dxf)")
);
if (!filename.isEmpty()) {
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this,
tr("Error"), tr("Could not open file"));
return;
}
}
}
void MainWindow::on_actionSave_triggered()
{
QString filename=QFileDialog::getSaveFileName(
this,
tr("Save File"),
QString(),
tr("file Name(*.txt)")
);
if(!filename.isEmpty()) {
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
return;
} else {
QTextStream stream(&file);
QTextEdit *textEdit;
stream << textEdit->toPlainText();
stream.flush();
file.close();
}
}
}
void MainWindow::on_actionQuit_2_triggered(){
MainWindow *window;
window->close();
}
void MainWindow::drawText(){
ui->graphicsView->setScene(scene);
text *item5 = new text;
scene->addItem(item5);
qDebug() << "text created";
connect(item5, SIGNAL(DrawFinished()), this, SLOT(drawText()));
}
MainWindow::~MainWindow()
{
delete ui;
}
text.h
#ifndef TEXT_H
#define TEXT_H
#include <QGraphicsTextItem>
#include <QPen>
#include<QFocusEvent>
#include<QGraphicsItem>
#include<QGraphicsScene>
#include<QGraphicsSceneMouseEvent>
#include<QGraphicsTextItem>
#include<QFont>
#include"mainwindow.h"
#include"ui_mainwindow.h"
class text:public QGraphicsTextItem
{
Q_OBJECT
public:
enum { Type = UserType + 3 };
enum Mode { InsertText };
void setFont(const QFont &font);
text(QGraphicsItem *parent = 0);
int type() const { return Type; }
public slots:
void setMode(Mode mode);
signals:
void lostFocus(text *item);
void selectedChange(QGraphicsItem *item);
void textInserted(QGraphicsTextItem *item);
void itemSelected(QGraphicsItem *item);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void focusOutEvent(QFocusEvent *event);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
private:
Mode myMode;
QFont myFont;};
#endif // TEXT_H
text.cpp
#include "text.h"
#include"mainwindow.h"
#include"ui_mainwindow.h"
text::text(QGraphicsItem *parent):QGraphicsTextItem(parent)
{
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
}
QVariant text::itemChange(GraphicsItemChange change,
const QVariant &value)
{
if (change == QGraphicsItem::ItemSelectedHasChanged)
emit selectedChange(this);
return value;
}
void text::focusOutEvent(QFocusEvent *event)
{
setTextInteractionFlags(Qt::NoTextInteraction);
emit lostFocus(this);
QGraphicsTextItem::focusOutEvent(event);
}
void text::setMode(Mode mode)
{
myMode = mode;
}
void text::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
if (textInteractionFlags() == Qt::NoTextInteraction)
setTextInteractionFlags(Qt::TextEditorInteraction);
QGraphicsTextItem::mouseDoubleClickEvent(event);
}
void text::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;
switch(myMode){
case InsertText:
text *textItem;
textItem = new text();
// textItem->setFont(myFont);
textItem->setPlainText("hello");
textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
textItem->setZValue(1000.0);
connect(textItem, SIGNAL(lostFocus(DiagramTextItem*)),
this, SLOT(editorLostFocus(DiagramTextItem*)));
connect(textItem, SIGNAL(selectedChange(QGraphicsItem*)),
this, SIGNAL(itemSelected(QGraphicsItem*)));
//addItem(textItem);
// textItem->setDefaultTextColor(myTextColor);
textItem->setPos(mouseEvent->scenePos());
emit textInserted(textItem);
//! [8] //! [9]
default:
;
}
// QGraphicsScene::mousePressEvent(mouseEvent);
}
Hm, if i am not mistaken, it does look like you are setting all kinds of properties of the text item, like Interaction-flags, z-value, color and so on -- everything but not the actual text. The text would be empty and therefore your QGraphicsTextItem will be invisible.
Use setPlainText(), setHtml() or setDocument() on your text item.
There are two places where text-items are created; one is in the mainwindow.cpp:
void MainWindow::drawText(){
ui->graphicsView->setScene(scene);
text *item5 = new text;
scene->addItem(item5);
qDebug() << "text created";
connect(item5, SIGNAL(DrawFinished()), this, SLOT(drawText()));
}
The text is created and added to the scene (with addItem()), but it does not have an actual content; set its content:
item5->setPlainText ("Mickey");
The second text-item is created from inside the text (which is a subclass of a QGraphicsTextItem) class itself:
void text::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
...
switch(myMode){
case InsertText:
text *textItem;
textItem = new text();
// textItem->setFont(myFont);
textItem->setPlainText("hello");
It is created correctly, and given a text, but not added to the scene. Add it to the scene, for instance by making it a child of the current text item:
textItem->setParentItem (this);

Scope issues with Qt Quick and C++ classes

I have a project that I am working on, that will hopefully result in C++ code with a QML UI as a console, communicating with other consoles and equipment.
My test setup is based on a RaspBerry Pi running UDP comms (works fine into a normal Qt application).
I have tried to port to Qt Quick, and use a simple QML UI, but if I declare the subclass early in my "main.cpp" it doesn't connect properly.
If I declare it in the main.cpp "main" function, then I have scope issues with the subclass functions that I want to use to transfer data.
Open to suggestions / critique......and I am 100% sure that there is a "proper" way of doing this, so if anyone wants to point me at it......I will be enraptured!
Qt version is Qt5.3.
import QtQuick 2.2
import QtQuick.Controls 1.1
Rectangle {
width: 440; height: 150
color: "orange"
Column {
anchors.fill: parent; spacing: 20
Text {
text: rootItem.theChange
font.pointSize: 12; anchors.horizontalCenter: parent.horizontalCenter
}
}
}
// signalgrab.h
#ifndef SIGNALGRAB_H
#define SIGNALGRAB_H
#include <QObject>
#include <QUdpSocket>
#include <QString>
class SignalGrab : public QObject
{
Q_OBJECT
public:
explicit SignalGrab(QObject *parent = 0);
int SendValue();
void setupUDP();
signals:
public slots:
void readyRead();
private:
QUdpSocket *socket;
QHostAddress groupAddress;
};
#endif // SIGNALGRAB_H
// signalgrab.cpp
#include "signalgrab.h"
int i3 = 0;
SignalGrab::SignalGrab(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
socket->bind(QHostAddress("0.0.0.0"), 45454);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
qDebug() << "Socket connected ok!";
}
void SignalGrab::readyRead()
{
// when data comes in
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(buffer.data(), buffer.size(),
&sender, &senderPort);
std::string s1 (buffer);
std::string s2 = s1.substr(26,sizeof(s1));
i3 = atoi(s2.data());
SendValue();
}
int SignalGrab::SendValue()
{
qDebug() << "sending i3 as: "<< i3;
return i3;
}
// main.cpp
#include <QtGui>
#include <QApplication>
#include <QQmlContext>
#include <QQuickView>
#include <QString>
#include "signalgrab.h"
int y=13;
// ///////////////////////////////////
//SignalGrab nc;
// ///////////////////////////////////
class Object : public QObject
{
Q_OBJECT
Q_PROPERTY(QString theChange READ getTheChange NOTIFY changeOfStatus)
public:
Object()
{
changeMe = false;
myTimer = new QTimer(this);
myTimer->start(5000);
connect(myTimer, SIGNAL(timeout()), this, SLOT(testSlot()));
}
QString getTheChange()
{
if (theValue == 0)
{
return "The Acid QML Test";
}
if (theValue == 1)
{
y = (fetchValue());
qDebug() << "New y!" << y;
return QString("Returning %1").arg(y);
}
return "nothing has happened yet";
}
int fetchValue()
{
// return (nc::SendValue());
return y;
}
Q_INVOKABLE void someFunction(int i)
{
if ( i == 0) {
theValue = 0;
}
if (i == 1) {
theValue = 1;
}
emit changeOfStatus(i);
}
signals:
void changeOfStatus(int i) ;
public slots:
void testSlot()
{
if (changeMe)
{
someFunction(0);
} else {
someFunction(1);
}
changeMe = !changeMe;
}
private:
bool changeMe;
int theValue;
QTimer *myTimer;
};
#include "main.moc"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Object myObj;
// //////////////////////////////
SignalGrab nc; //added
// //////////////////////////////
nc.SendValue();
QQuickView view;
view.rootContext()->setContextProperty("rootItem", (QObject *)&myObj);
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}

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.