Update QProgressBar from QFutureWatcher - qt

I am trying to update QProgressBar from QFutureWatcher. But the progress bar is not updated. Signals do not reach the progress bar. Here is my code:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto* progress = ui->progressBar;
QObject::connect(&futureWatcher, &QFutureWatcher<void>::finished, progress, &QProgressBar::reset);
QObject::connect(ui->stopBtn, &QPushButton::clicked, &futureWatcher, &QFutureWatcher<void>::cancel);
QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressRangeChanged, progress, &QProgressBar::setRange);
QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, progress, &QProgressBar::setValue);
}
std::function<void(int&)> spin = [](int& iter) {
const int work = 1000 * 1000 * 40;
volatile int v = 0;
for (int j = 0; j < work; ++j)
++v;
qDebug() << "iteration " << iter << " in thread" << QThread::currentThreadId();
};
void MainWindow::on_startButton_clicked()
{
for (int i =0; i < 200; i++)
m_list.push_back(i);
qDebug() << QString("Progressing using %1 thread(s)...").arg(QThread::idealThreadCount());
m_fututre = QtConcurrent::map(m_list, spin);
futureWatcher.setFuture(m_fututre);
}
Does anyone know how to fix this problem?

Related

QThreadPool: Is it ok to setExpiryTimeout(-1) or maybe I'm misusing the Threads?

I'm experimenting with QThreadPool and realized that my program exited with SIGSEGV after QThreadPool reaches expiry timeout.
I started the program creating pointers to QLabel and QLineEdits as placeholders, which are kept in QLists.
Then, the method carregar2() is called, when the menu is clicked, to start the QThreadPool.
I implemented 4 QRunnables. They're all the same: they invoke external program (QProcess) with different parameters. Their result are written to QLineEdits.
If I set setExpiryTimeout(-1), the program does not crash.
This is the MainWindow class, it is the called from the main.cpp :
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtWidgets>
#include "ClickableLabel.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QMainWindow::showMaximized();
ui->setupUi(this);
QStringList args = QApplication::arguments();
QString path;
if(args.size()<=1)
path = QFileDialog::getExistingDirectory(parent, "", "/studio/FOTOS", QFileDialog::ShowDirsOnly);
else
path = static_cast<QString>(args.at(1));
QDir *dir = new QDir(path);
setWindowTitle("QExif - " + path);
QScrollArea *scroll = new QScrollArea();
QGridLayout *grid = new QGridLayout(scroll);
QFrame *frame = new QFrame();
int row=0;
int col=0;
QStringList filtro;
filtro << "*.jpg";
const QFileInfoList fil = dir->entryInfoList(filtro,QDir::Files );
qDebug() << "FOTOS: " << fil.size();
foreach (QFileInfo fi, fil ) {
QString f = fi.absoluteFilePath();
QLabel *l = new ClickableLabel(); //A custom QLabel that implements a clicked() signal and "emit clicked()" on mousePressEvent
l->setStyleSheet("border: 5px solid white");
l->setMaximumSize(w,h);
l->setMinimumSize(w,h);
l->setProperty("foto", f);
l->setToolTip(f);
connect(l, SIGNAL(clicked()), this, SLOT(abrirVisualizadorExterno()));
grid->addWidget(l,row,col,1,1,Qt::AlignTop);
//tag buttons
QHBoxLayout *box = new QHBoxLayout(parent);
QFrame *btnFrame = new QFrame();
btnFrame->setLayout(box);
btnFrame->setMaximumWidth(w);
QLineEdit *tagArtista = new QLineEdit(parent);
tagArtista->setToolTip("Etiquetas");
grid->addWidget(tagArtista,row+1,col,1,1,Qt::AlignTop);
QLineEdit *tagDescricao = new QLineEdit(parent);
tagDescricao->setToolTip("Descrição da imagem");
grid->addWidget(tagDescricao,row+2,col,1,1,Qt::AlignTop);
QLineEdit *tagDataHora = new QLineEdit(parent);
tagDataHora->setToolTip("Data e Hora");
grid->addWidget(tagDataHora,row+3,col,1,1,Qt::AlignTop);
tagArtista->setProperty("foto", f);
tagDescricao->setProperty("foto", f);
tagDataHora->setProperty("foto", f);
fList->append(f);
labelList->append(l);
tagList->append(tagArtista);
descricaoList->append(tagDescricao);
dataHoraList->append(tagDataHora);
col++;
if(col >3) { col=0; row+=4; }
} //foreach
frame->setLayout(grid);
scroll->setWidget(frame);
setCentralWidget(scroll);
/*
* MENU
* */
QMenu *menuExif = ui->menuBar->addMenu("Exif");
menuExif->addAction("Carregar");
connect(menuExif,SIGNAL(triggered(QAction*)),this,SLOT(menuHandler(QAction*)));
}
void MainWindow::menuHandler(QAction *action){
if(action->text() == "Carregar"){
carregar2();
}
}
void MainWindow::carregar2(){
QThreadPool *pool = QThreadPool::globalInstance();
pool->setExpiryTimeout(-1);
for(int i=0; i<fList->count(); i++){
ImagemRunnable *imageRunnable = new ImagemRunnable(labelList->at(i), fList->at(i), w, h);
QThreadPool::globalInstance()->start(imageRunnable);
TagRunnable *tagRunnable = new TagRunnable(tagList->at(i), fList->at(i));
pool->start(tagRunnable);
TagDescricaoRunnable *tagDescricaoRunnable = new TagDescricaoRunnable(descricaoList->at(i), fList->at(i));;
pool->start(tagDescricaoRunnable);
TagDataHoraRunnable *tagDataHoraRunnable = new TagDataHoraRunnable(dataHoraList->at(i), fList->at(i));
pool->start(tagDataHoraRunnable);
}
}
void MainWindow::abrirVisualizadorExterno(){
ClickableLabel *l = (ClickableLabel *) sender();
qDebug() << "Abrir" << l->property("foto");
if (l->property("foto").isValid()){
QStringList cmd;
cmd << QString("eog %1").arg(l->property("foto").toString());
system(cmd.at(0).toUtf8().data());
}
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event){
qDebug() << watched->property("foto").toString();
return false;
}
MainWindow::~MainWindow()
{
delete ui;
}
And this is one of the implemented QRunnables:
header:
#ifndef TAGRUNNABLE_H
#define TAGRUNNABLE_H
#include <QRunnable>
#include <QLineEdit>
class TagRunnable : public QRunnable, QObject
{
public:
TagRunnable(QLineEdit * f, QString file);
void run() override;
private:
QLineEdit *field;
QString file;
};
#endif // TAGRUNNABLE_H
cpp:
#include "tagrunnable.h"
#include <QProcess>
#include <QDebug>
TagRunnable::TagRunnable(QLineEdit * f, QString file)
{
field = f;
this->file = file;
}
void TagRunnable::run(){
QProcess *proc = new QProcess();
//pessoas na foto
proc->start("/usr/bin/exif", QStringList()
<< "-t" << "0x013b"
<< "-m"
<< file
);
if(!proc->waitForFinished()){
qDebug() << "Timeout ao ler exif tag (pessoas)." << file;
}
field->setText(proc->readAllStandardOutput());
field->setProperty("tagOriginal", field->text());
}
My questions:
Suppose I use 30 seconds as expiry timeout. After that time, is my reference to the QProcess removed from memory and causing the QLineEdit text to be lost as well?
Is it ok to set expiry timeout to -1 in any situation or, perhaps, I'm not using it properly because of other architectural error of my program ?

Qt Grid add cutting lines

Such like title I say,
The game.cpp:
#include "game.h"
#include "ui_game.h"
#include "qdebug.h"
Game::Game(QWidget *parent) :
QWidget(parent),
ui(new Ui::Game)
{
ui->setupUi(this);
QPalette palette;
QPixmap pixmap(":/bgimg");
palette.setBrush(this->backgroundRole(),QBrush(pixmap));
this->setPalette(palette);
InitLayout(6,6);
}
Game::~Game()
{
delete ui;
}
void Game::InitLayout(int widthNum, int heightNum)
{
ui->grid->setGeometry(QRect(0,0,1000,800));
for(int i=0; i< heightNum;i++)
{
for(int j=0;j<widthNum;j++)
{
int total = i*10+j;
QString s = QString::number(total);
qDebug() << s << "\n";
QLabel*item = new QLabel(this);
//item->setText(s);
ui->grid->addWidget(item,i+1,j+1);
}
}
}
And cell.cpp
#include "cell.h"
cell::cell(QWidget *parent):
QLabel(parent)
{
this->setGeometry(0,0,20,20);
QPixmap qpixmap(":/qizi");
this->setPixmap(qpixmap);
}
I want to show the cutting line int Grid(You know that grid are divided into many cell by line). I can't find to property in Grid.

Why is the clicked() signal for the QPieSlice not emitted?

I'm using Qt charts module to draw a Nested Donuts chart just like the example in Qt Charts.
And I want every components (QPieSlice) response to the mouse event, the hovered() signals work well, however, the clicked() signals only work for the QpieSlices in the last added QPieSerie. It seems other QpieSlices do not emit the signals, since if I explicitly call the clicked() function, the slot response correctly.
This piece of code shows the issue
Widget::Widget(QWidget *parent): QWidget(parent){
QChartView *chartView = new QChartView;
QChart *chart = chartView->chart();
for (int i = 0; i < donutCount; i++) {
QPieSeries *donut = new QPieSeries;
donut->setHoleSize(minSize + i * (maxSize - minSize) / donutCount);
donut->setPieSize(minSize + (i + 1) * (maxSize - minSize) / donutCount);
int sliceCount = 3 + qrand() % 3;
for (int j = 0; j < sliceCount; j++) {
qreal value = 100 + qrand() % 100;
QPieSlice *slice = new QPieSlice(QString("%1").arg(value), value);
slice->setLabelVisible(true);
slice->setLabelColor(Qt::white);
slice->setLabelPosition(QPieSlice::LabelInsideTangential);
connect(slice, SIGNAL(hovered(bool)), this, SLOT(explodeSlice(bool)));
connect(slice, SIGNAL(clicked()), this, SLOT(selected()));
donut->append(slice);
}
m_donuts.append(donut);
chartView->chart()->addSeries(donut);
}
void Widget::selected()
{
QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
cout << slice->label().toStdString() << endl;
}
What am I doing wrong? Can someone help me?

Camera opens with grey color on window7 using cvCaptureFromCAM function in VS 2013

My camera opens grey in color,Why does this happen?
Heres the capture function part of code..
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
//An Array of the pattern alphabets
stopCapture = true;
alphabetTable[0]="A.jpg";
alphabetTable[1]="B.jpg";
alphabetTable[2]="C.jpg";
alphabetTable[3]="D.jpg";
alphabetTable[4]="E.jpg";
alphabetTable[5]="F.jpg";
color = cvScalar(0x00, 0x00, 0xff);
showGray = false;
startmatching = false;
timer1 = new QTimer(this);
connect(timer1, SIGNAL(timeout()), this, SLOT(stopped_timer()));
ui->setupUi(this);
}
//Start the capture function
void MainWindow::Capture(){
float matchresult = 1;
p_capWebcam = cvCaptureFromCAM(0);
cvNamedWindow("Original", CV_WINDOW_AUTOSIZE);
if (p_capWebcam != NULL)
{
while (true)
{
IplImage *frame = cvQueryFrame(p_capWebcam);
cvShowImage("WEBCAM_TEST", frame);
cvWaitKey(20);
}
}
else
{
std::cout << "CAMERA NOT DETECTED" << std::endl;
}
IplImage * tableauxImage[6];
for (int i = 0; i<6; i++)
{
tableauxImage[i] = cvLoadImage(alphabetTable[i], CV_LOAD_IMAGE_GRAYSCALE);
}
while (1){
p_imgOriginal = cvQueryFrame(p_capWebcam);
p_gray = cvCreateImage(cvGetSize(p_imgOriginal), 8, 1);
cvFlip(p_imgOriginal, p_imgOriginal, 1);
cvCvtColor(p_imgOriginal, p_gray, CV_BGR2GRAY);
cvSetImageROI(p_gray, cvRect(100, 100, 200, 200));
cvThreshold(p_gray, p_gray, 100, 255, CV_THRESH_BINARY_INV);
MainWindow::draw_box(p_imgOriginal, cvRect(100, 100, 200, 200));
// when show Roi Button is clicked
if (showGray == true) {
cvNamedWindow("template gray", CV_WINDOW_AUTOSIZE);
cvShowImage("template gray", p_gray);
}
cvShowImage("Original", p_imgOriginal);
for (int i = 0; i<6; i++){
if (startmatching == true)
matchresult = MainWindow::match_two_shapes(tableauxImage[i], p_gray);
if (matchresult<0.1){
ui->signname->setText(QString(convertstring(alphabetTable[i])[0])); //good match
timer1->start(1000);
}
else {
if (matchresult<0.25)
color = cvScalar(0x00, 0xff, 0x00);
else
color = cvScalar(0x00, 0x00, 0xff);
}
ui->matchresultlabel->setText(QString::number(matchresult));
}
charCheckForEscKey = cvWaitKey(ui->Delais->value());// delay (in ms), and get key press, if any
if ((charCheckForEscKey == 27) || (stopCapture))
break;
}
for (int i = 0; i < 6; i++)
{
cvReleaseImage(&tableauxImage[i]);
}
cvReleaseCapture(&p_capWebcam);
cvDestroyAllWindows();
}
I am using Windows 7 OS with my inbuilt lenovo camera
A simple opencv program to open camera works fine..and also using VS2013 with opencv 3.3.0 and qtcreator for gui
How can my camera open to capture images ...What is wrong with the code??
Please help..!!

Read and write to a file from a QTableView

How can I read and write to a text file date enter to a QTableView?
This is what I have but I would like to save the data when it is added to the table and of course be able to read it back when the application is reopened. Is there any tutorial I can refer to?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
model = new QStandardItemModel();
model->setRowCount(0);
ui->tableView->setModel(model);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QStandardItem *userName = new QStandardItem(ui->lineEdit_Name->text());
QStandardItem *userNumber = new QStandardItem(ui->lineEdit_Number->text());
QList<QStandardItem*> row;
row <<userName << userNumber;
model->appendRow(row);
}
Thanks a lot
EDIT --------------------------------
This is what worked for me:
Add Function:
void MainWindow::on_pushButto_Add_clicked() {
QStandardItem *userInput = new QStandardItem(ui->lineEdit->text());
QStandardItem *userInput2= new QStandardItem(ui->lineEdit_2->text());
QList<QStandardItem*> row;
row <<userInput << userInput2;
model->appendRow(row);
}
Save Function:
void MainWindow::on_pushButton_Save_clicked()
{
QFile file("C:/Users/UserName/Practicing/Resources_Files/someFile.bin");
if (file.open(QIODevice::WriteOnly))
{
QDataStream stream(&file);
qint32 n = model->rowCount();
qint32 m = model->columnCount();
stream << n << m;
for (int i=0; i<n; ++i)
{
for (int j=0; j<m; j++)
{
model->item(i,j)->write(stream);
}
}
file.close();
}
}
Load Function:
void MainWindow::on_pushButton_Load_clicked()
{
QFile file("C:/Users/UserName/Practicing/Resources_Files/someFile.bin");
if (file.open(QIODevice::ReadOnly))
{
QDataStream stream(&file);
qint32 n, m;
stream >> n >> m;
model->setRowCount(n);
model->setColumnCount(m);
for (int i = 0; i < n ; ++i) {
for (int j = 0; j < m; j++) {
QStandardItem *item = new QStandardItem;
item->read(stream);
model->setItem(i, j, item);
}
}
file.close();
}
}
QFile file("somefile.bin");
if (file.open(QIODevice::WriteOnly)) {
QDataStream stream(&file);
stream << *(model->invisibleRootItem());
file.close();
}
http://qt-project.org/doc/qt-5.0/qtgui/qstandarditemmodel.html#invisibleRootItem
Edit:
Here is correction (I've checked that it works).
void MainWindow::save()
{
QFile file("somefile.bin");
if (file.open(QIODevice::WriteOnly)) {
QDataStream stream(&file);
qint32 n(model->rowCount()), m(model->columnCount());
stream << n << m;
for (int i=0; i<n; ++i)
for (int j=0; j<m; j++)
model->item(i,j)->write(stream);
file.close();
}
}
void MainWindow::load()
{
QFile file("somefile.bin");
if (file.open(QIODevice::ReadOnly)) {
QDataStream stream(&file);
qint32 n, m;
stream >> n >> m;
model->setRowCount(n);
model->setColumnCount(m);
for (int i=0; i<n; ++i)
for (int j=0; j<m; j++)
model->item(i,j)->read(stream);
file.close();
}
}
You can browse your model row by row, column by column and fill a file with a format like CSV (a row by line and columns separated by coma or tabs).
But, I don't think that is a good idea to modify the file when an item has changed. You should write the file when your application is closed.
model->item(i,j)->write(stream); will lead to segmentation fault if item(i,j) is empty. Assign some dummy value like whitespace in empty cells.

Resources