Get duration of QMediaPlaylist object - qt

I create a player for audiobooks - when you open a folder with mp3 file, whole list of them is added to playlist and List View. And i have a Label, which suppose to show duration of the whole book. But player->duration returns only a duration of current track, and if i go through the loop and do playlist->next() every step, player->duration returns 0. I know about Phonon and file metadata, but i need to do this without using it.

I am attaching a source code of a working project, you can use. When the player changes the file, the duration is changed and printed out. To loop within files, there is a need to wait till the decoder completes reading the media file. See the code below and the comments.
This is mainwindow.cpp
#include "mainwindow.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
bool done =false;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
player = new QMediaPlayer(this);
playlist = new QMediaPlaylist(player);
playlist->setPlaybackMode(QMediaPlaylist::Sequential);
player->setPlaylist(playlist);
connect(player, &QMediaPlayer::durationChanged, this, &MainWindow::on_durationchanged);
//connect(player,&QMediaPlayer::)
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
playlist->addMedia(QUrl::fromLocalFile("Ar_today.mp3"));
playlist->addMedia(QUrl::fromLocalFile("Ar_sunday.mp3"));
playlist->setCurrentIndex(0); //set the first file
while (done == false) //wait till the duration is read
{
QApplication::processEvents();
}
done = false; playlist->setCurrentIndex(1); //change to the second file
while (done == false) //wait till the duration is read
{
QApplication::processEvents();
} //this way you can loop through files
player->setVolume(80);
player->play();
qDebug() << player->errorString();
}
void MainWindow::on_pushButton_2_clicked()
{
player->stop();
}
void MainWindow::on_durationchanged(qint64 duration)
{
done = true;
qDebug() << "duration = " << player->duration();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QDebug>
extern bool done;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_durationchanged(qint64 duration);
private:
Ui::MainWindow *ui;
QMediaPlayer* player;
QMediaPlaylist* playlist;
};
#endif // MAINWINDOW_H
In the form, create 2 buttons, one called pushbutton to play and the other is pushButton_2 to stop

Related

Qt : How to start , stop and delete thread?

=====================OUTDATE=======================
I have a vector which contains threads, each thread is doing a while loop, for some reason, i need to delete the thread in the vector, to do this, i referenced this blog and write a test demo online. But when i write pthread_cancel() in Qt, it reports error: use of undeclared identifier 'pthread_cancel'. I have added LIBS += -lpthread in my .pro file and added #include <thread> in my .cpp file, this error still exists.
=====================UPDATE=====================
Afterwards, i trid to use QThread to achieve my goal. In brief, to start a qthread, i create a Worker class, then instantiate it and move it to QThread, connect &QThread::started with &Worker::process, process is the time consuming method, finnaly call thread->start();; to stop a qthread, i use a bool flag, and i store it with thread id in QMap, if the bool flag is set to false, qthread will break while loop, and emit a finished() signal and this signal will trigger &QThread::quit; to delete the qthread, i connect finished() signal with &Worker::deleteLater and &QThread::deleteLater.
The code are:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"
#include <QThread>
#include <QMap>
#include <QDebug>
QMap<int, bool> stateController;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
qDebug()<<"Main UI thread id is"<<(int)QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_add_clicked()
{
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//hold a place for blank item, in order to uniformly determine whether its text is empty afterwards
QTableWidgetItem *ckx = new QTableWidgetItem;
ckx->setCheckState(Qt::Unchecked);
ui->tableWidget->setItem(row,1,ckx);
}
void MainWindow::on_tableWidget_cellClicked(int row, int column)
{
if(column == 1){
bool state = ui->tableWidget->item(row,1)->checkState();
if(state){
if(ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is not thread id, then create the thread
QThread* thread = new QThread();
qDebug()<<"New created thread id is"<<(int)thread->currentThreadId(); //I found this thread id will equal to main ui thread id, so i use a sigal/slot to update thread id
Worker* worker = new Worker(row);
worker->moveToThread(thread);
connect( worker, &Worker::updateQThreadIDSignal, this, &MainWindow::updateQThreadID);
connect( thread, &QThread::started, worker, &Worker::process);
connect( worker, &Worker::finished, thread, &QThread::quit);
// automatically delete thread and worker object when work is done:
connect( worker, &Worker::finished, worker, &Worker::deleteLater);
connect( thread, &QThread::finished, thread, &QThread::deleteLater);
//start the thread
thread->start();
}
}else{
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is already the thread, then stop it
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
// qDebug()<<"get thread id is"<<thread_id;
QMutexLocker locker(&mx);
stateController[thread_id] = false;
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//Because thread will be delete later, so clear its thread id
}
}
}
}
void MainWindow::on_pushButton_delete_clicked()
{
QItemSelectionModel* selectionModel = ui->tableWidget->selectionModel();
QModelIndex index = selectionModel->currentIndex();
if(index.isValid()){
int row = index.row();
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//Before stop the thread, ensure it exist
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
if(ui->tableWidget->item(row,1)->checkState() == Qt::Checked){
//If not stopped yet, firstly stop it
QMutexLocker locker(&mx);
stateController[thread_id] = false;
}
stateController.remove(thread_id);
}
ui->tableWidget->removeRow(row);
}
}
void MainWindow::updateQThreadID(int row, QString id)
{
ui->tableWidget->setItem(row,0,new QTableWidgetItem(QString::number(id.toInt())));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMutex>
#include <vector>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_add_clicked();
void on_tableWidget_cellClicked(int row, int column);
void on_pushButton_delete_clicked();
public slots:
void updateQThreadID(int row, QString id);
private:
Ui::MainWindow *ui;
QMutex mx;
};
#endif // MAINWINDOW_H
worker.cpp
#include "worker.h"
#include <QThread>
#include <QDebug>
#include <QMutexLocker>
extern QMap<int, bool> stateController;
Worker::Worker(int row) : row_index(row) {
qDebug()<<"Create new worker at thread "<<(int)QThread::currentThreadId();
}
Worker::~Worker() {
qDebug()<<"Destroy the worker instance";
}
void Worker::process() {
thread_id = (int)QThread::currentThreadId();
stateController.insert(thread_id, true);
// qDebug()<<"set thread id is"<<thread_id;
emit updateQThreadIDSignal(row_index,QString("%1").arg(thread_id)); //execute once, because if delete row happen, the row index will change
while(true)
{
count++;
QThread::sleep(2);//simulate time consuming operations
qDebug()<<thread_id<<"processing"<<count;
{//life scope of locker
QMutexLocker locker(&mx);
if(!stateController[thread_id])//In every loop, determine whether it can run, if not, exit the loop
{
return;
}
}
}
emit finished();
}
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject {
Q_OBJECT
public:
Worker(int row);
~Worker();
public slots:
void process();
signals:
void finished();
void updateQThreadIDSignal(int, QString);
private:
int thread_id;
int row_index;
QMutex mx;
int count = 0;
};
#endif // WORKER_H
To watch the demo video, click here.
If you have any advice, please let me know, thanks !
Even though the codes seems to work fine, but i still have a question : Why i wrote &Worker::deleteLater, but I never see the destructor of Worker is called ?

Qt QTreeView indexBelow does not work

As far as I understood, indexBelow function is used for navigating to the next item on a tree in Qt's QTreeView. I want to write two functions - one to move to next item, one to move to previous item in a DirModel based TreeView. However, indexBelow does only work once.
Considering ui is the UI variable, the following is my function to move to the next item
void MainWindow::moveDown (void)
{
QModelIndex index_it = ui->treeView->indexBelow(ui->treeView->currentIndex());
qDebug() << index_it.row();
if (index_it.isValid())
{
qDebug() << "Valid";
ui->treeView->setCurrentIndex(index_it);
ui->treeView->selectionModel()->select(index_it, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
}
When a button is pressed, this will be triggered and the tree will be navigated using buttons. This however, works only once, and afterwards stops working. Note that I want to be able to move to next item even if there is an expanded child. Any pointers and help is greately appreciated.
Just tried your code and it work fine.
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QStandardItemModel>
#include <QFileSystemModel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
model->setReadOnly(false);
model->setSorting(QDir::DirsFirst |
QDir::IgnoreCase |
QDir::Name);
ui->treeView->setModel(model);
index = model->index("C:/");
// Set initial view of directory
// for the selected drive as expanded
ui->treeView->expand(index);
// Make it scroll to the selected
ui->treeView->scrollTo(index);
// Highlight the selected
ui->treeView->setCurrentIndex(ui->treeView->indexBelow(index));
// Resizing the column - first column
ui->treeView->resizeColumnToContents(0);
}
void MainWindow::on_pushButton_3_clicked()//<------Your function MoveDown
{
QModelIndex index_it = ui->treeView->indexBelow(ui->treeView
->currentIndex());
qDebug() << index_it.row();
if (index_it.isValid())
{
qDebug() << "Valid";
ui->treeView->setCurrentIndex(index_it);
ui->treeView->selectionModel()->select(index_it, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
}
And mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QModelIndex>
#include <QDirModel>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
emitProgress(int per)
{
emit signalProgress(per);
}
void on_pushButton_clicked();
void on_pushButton_3_clicked();
signals:
private:
Ui::MainWindow *ui;
QModelIndex index;
QDirModel* model = new QDirModel(this);
};

'QMessageBox::critical' : none of the 4 overloads could convert all the argument types

I want to display an error message whenever my independent thread encounters the word "alert1" in a specific .txt file. But I get the above error inside the monitorForAlerts() inside mythread.cpp file. The line expectedly executes if I were to place it inside dialog.cpp. So I guess this is due to non-inheritance of this object. Can you please advise me how to solve this error for the given code?
Here is the code:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtCore>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
private:
Ui::Dialog *ui;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#include <QFile>
#include <Windows.h>
#include <QMessageBox>
#include <QTimer>
#define ALERTS_MESSAGE_STORAGE_PATH "E:\\QT1\\simpleGUIThread2\\simpleGUIThread2\\usbAlert.txt"
#define TIMER_VALUE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
void monitorForAlerts();
int exec();
public slots:
signals:
void testSignal(QString message);
public slots:
};
#endif // MYTHREAD_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_pushButton_clicked()
{
ui->label->show();
}
void Dialog::on_pushButton_2_clicked()
{
ui->label->hide();
}
mythread.cpp
#include "mythread.h"
#include "dialog.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
monitorForAlerts();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::monitorForAlerts()
{
QString response = ALERTS_MESSAGE_STORAGE_PATH;
QFile resp(response);
resp.open(QIODevice::WriteOnly);
resp.close();
QFile resp1(response);
char buf[121];
char buf1[] = "alert1";
char buf2[] = "alert2";
resp1.open(QIODevice::ReadOnly);
while(resp1.size() == 0)
{
Sleep(3000);
}
qint64 lineLength = resp1.readLine(buf, sizeof(buf));
resp1.close();
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
}
if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
}
main.cpp
#include "dialog.h"
#include <QApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
w.show();
return a.exec();
}
LATEST UPDATE*********************************************************************
Hi Zlatomir,
I choose to take your 1st advice. I have created a signal that the thread will emit and connect it to a slot for QDialog. Please let me know if my understanding is correct, because I do not know where to implement the connect(), since the signal is declared in mythread.h and the slot in dialog.h. The connection type argument for connect is Qt::QueuedConnection, so that gui elements from another thread different than main-thread.
are NOT created. Is this statement correct? and where do I place this?
connect( mThread, SIGNAL(alertSignal(QString)), this, SLOT(alertSlot(QString)), Qt::QueuedConnection);
mythread.h
//....
signals:
void alertSignal(QString message);
//....
dialog.h
//....
public slots:
void alertSlot(QString message);
//....
mythread.cpp
//....
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
emit(alertSignal("alert1"));
}
else if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
emit(alertSignal("alert2"));
}
dialog.cpp
void Dialog::alertSlot(QString message)
{
if(strcmp(message, "alert1"))
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
else if(strcmp(message, "alert2"))
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
Now if this were correct, how do i implement the connect() and in which file?
The first argument is the problem, in your case this is not a good argument, because there this is a pointer to a MyThread instance, and MyThread is not a QWidget (is not derived from QWidget).
To solve this you can show the QMessageBox::critical from a slot in mainwindow (the Dialog class in your code, there you pass the instance of main-window that is a QWidget) and connect that slot with a signal that you emit from your thread, make sure that the connection type argument for connect is Qt::QueuedConnection, so that you don't try to create gui elements from another thread different than main-thread.
Another option would be to validate the data before you start the second thread and to tell
the user that he needs to provide the right files.
LE: Also check the QThread's documentation for the recommended way to use the class, now it's recommended not to derive from QThread.
LE2 - answer to the update
That connect can be made where ever you can have the two instances that you want to connect, in your case main.cpp is a good place to connect those (don't forget to fully qualify the name for connect: QObject::connect):
//...
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
QObject::connect( &mThread1, SIGNAL(alertSignal(QString)), &w, SLOT(alertSlot(QString)), Qt::QueuedConnection);
w.show();
//...

Qt debug pointer not following expected flow in 2nd and successive iterations

I want to display a "generating image..." kind of modal dialog, other than the main GUI. This "generating image..." dialog should be temporary, and be displayed and disappear without user intervention.
For displaying this dialog, the Qt code should check for existence of a .txt file in a specific location in the PC's hard disk. If the .txt file exists, then the dialog should pop-up.
For making this dialog disappear, the Qt code should check whether that .txt file contains the string "OK" in the first line. The dialog should disappear only when this "OK" is found, until then it should continue to display "generating image..."
A good way to do this is to use signal slot mechanism. I would like to know, what functions should be used as SIGNALS in both the cases, of displaying and removing the dialog.
So far, I could manage a simple code, illustrating a "generating image..." using signal slot mechanism, but with setValue() and pressing a push button(i.e. involving user intervention), and not with the checking of .txt file or the "OK" string inside that .txt file(user non-intervention).
Please advise me, whether my logic can be implemented? If yes, how? Also, what SIGNALs should be used?
************************UPDATED SECTION(as of Feb 24th '14):****************************************************
I have revised the code according to Dmitry Sazonov's suggestions. I am able to display the loading GIF whenever a new file is created/deleted in a designated directory. Now I want to close this loading qDialog, when the usbResponse.txt file has "ok" inside it. I tried using signal slot, to implement hide(), but could not get it.
I do not get errors, but the qDialog window does not close as expected. I tried both, secDialog.close() and secDialog.hide(), but the window didn't close. Perhaps because the secDialog object is not the same in both the SLOTs. So I also made secDialog, a global object, but I received an error as follows:-
QWidget: Must construct a QApplication before a QWidget
I looked it up: https://qt-project.org/forums/viewthread/12838
Changed the build modes, accordingly, but that didn't help either. Please tell me how do I close my qDialogs, when I find the "ok" in usbResponse.txt file.
************************UPDATED SECTION(as of Mar 14th '14):****************************************************
I could close the qDialog containing the GIF using hide(). I have done a total overhaul of the code. As mentioned above, the qDialog containing the GIF should appear whenever a text file called usbResponse.txt exists at a designated location. Also taking #Dmitry Sazonov's advice, I am able to close the GIF whenever that txt file i.e. usbResponse.txt is modified, using FileSystemWatcher.
I'm continuously scanning for the existence of the .txt using threads. When I find the file, I display the loading GIF. When the .txt is modified the GIF should disappear. This works fine for the first iteration, i.e. when
(the following are observations after debugging)
the usbResponse.txt exists => GIF is displayed
when usbResponse.txt is modified => GIF is hidden & the .txt is deleted.
THe problem, in next iteraiton,(i.e. all iterations after the first)
the usbResponse.txt is created => the GIF is displayed.
when usbResponse.txt is modified, the debug pointer continues to remain in
afterFileHasBeenFound()
whereas it should have gone in
closeModified(const QString &str)
What is my mistake here?
Here is my code:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFile>
#include <QDebug>
#include <QFileSystemWatcher>
#include "dialog.h"
#include "mythread.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void afterFileHasBeenFound();
void closeModified(const QString &str);
private slots:
private:
Ui::MainWindow *ui;
Dialog *pDialog;
MyThread *mThread;
};
#endif // MAINWINDOW_H
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QMovie>
#include <QLabel>
#define GIF_PATH "E:\\QT1\\timeStampPopUp\\timeStampPopUp\\loading.gif"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
void displayLoadingGif();
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#define FILE_PATH "E:\\QT1\\dialogClose2\\dialogClose2\\usbResponse.txt"
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
int exec();
void checkFile();
signals:
void testSignal(QString message);
void fileFoundDisplayGif();
public slots:
};
#endif // MYTHREAD_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
displayLoadingGif();
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::displayLoadingGif()
{
QMovie *pMovie = new QMovie(GIF_PATH);
ui->loadingGifLabel->setMovie(pMovie);
pMovie->start();
}
mythread.cpp
#include "mythread.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
checkFile();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::checkFile()
{
QFile file(FILE_PATH);
if(file.exists())
{
qDebug()<<"exists";
emit(fileFoundDisplayGif());
}
else
qDebug()<<"doesn't exist";
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mThread = new MyThread(this);
mThread->name = "mThread";
connect(mThread, SIGNAL(fileFoundDisplayGif()), this, SLOT(afterFileHasBeenFound()), Qt::QueuedConnection);
mThread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::afterFileHasBeenFound()
{
if(pDialog != NULL)
return;
pDialog = new Dialog();
pDialog->setModal(true);
pDialog->show();
}
void MainWindow::closeModified(const QString &str)
{
Q_UNUSED(str)
if(pDialog != NULL)
{
pDialog->hide();
}
QFile file(FILE_PATH);
file.remove();
pDialog = NULL;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileSystemWatcher fileWatcher;
fileWatcher.addPath(FILE_PATH);
QStringList fileList = fileWatcher.files();
Q_FOREACH(QString file, fileList)
qDebug() << "File name " << file;
MainWindow* mc = new MainWindow;
QObject::connect(&fileWatcher, SIGNAL(fileChanged(QString)), mc, SLOT(closeModified(QString)));
mc->show();
return a.exec();
}
Do not use timers for checking file. Use QFileSystemWatcher for traking file modifications.
Implement a slot that will check file content on modification. And call hide() method, when your "OK" text appeared.
IMHO: your solution is to messy. There are a lot of other syncronization mechanisms between processed. Can you modify code of tool that generates image? Should it really work as another process?

Cannot read output using readyReadStandardOutput in Qt

I am using Qt and I am unable to get output of a exe file using readyReadStandardOutput.
Here is my code.
mainwindow.cpp
void MainWindow::on_pushButton_24_clicked()
{
myprocess = new QProcess(this);
myprocess->start("files\\helloworld.exe");
connect(myprocess, SIGNAL(readyReadStandardOutput ()), this, SLOT(outlog()));
}
void MainWindow::outlog()
{
QString abc;
abc = myprocess->readAllStandardOutput();
emit outlogtext(abc);
ui->lineEdit_4->setText(abc);
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QProcess *myprocess;
signals:
void outlogtext(QString ver);
private slots:
void outlog();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
The helloworld.exe will just give a output "Hello world" but I cannot see it in the textEdit, whats wrong with my code? I am very new to Qt. Thank you
I got the program working. Below is the code.
mainwindow.hpp
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include <QtGui>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void outlogtext(QString ver);
private slots:
void outlog();
void on_pushButton_24_clicked();
private:
QPushButton* pushButton_24;
QLineEdit* lineEdit_4;
QProcess *myprocess;
};
#endif // MAINWINDOW_HPP
main.cpp
#include <QtCore>
#include <QtGui>
#include <QDebug>
#include "mainwindow.hpp"
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
{
pushButton_24 = new QPushButton;
connect(pushButton_24, SIGNAL(clicked()),
this, SLOT(on_pushButton_24_clicked()));
lineEdit_4 = new QLineEdit;
QWidget* central = new QWidget;
QLayout* layout = new QVBoxLayout();
layout->addWidget(pushButton_24);
layout->addWidget(lineEdit_4);
central->setLayout(layout);
setCentralWidget(central);
}
MainWindow::~MainWindow()
{
}
void MainWindow::on_pushButton_24_clicked()
{
myprocess = new QProcess(this);
connect(myprocess, SIGNAL(readyReadStandardOutput()),
this, SLOT(outlog()));
myprocess->start("./helloworld.exe");
// For debugging: Wait until the process has finished.
myprocess->waitForFinished();
qDebug() << "myprocess error code:" << myprocess->error();
}
void MainWindow::outlog()
{
QString abc = myprocess->readAllStandardOutput();
emit outlogtext(abc);
lineEdit_4->setText(abc);
}
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow win;
win.show();
return app.exec();
}
helloworld.cpp
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
}
Some things I changed:
After constructing an object, I always connect signals and slots before performing the
actual operation on the object, which might be calling show() for widgets or calling
start() for threads. So I can be sure that I do not miss a signal like started(),
for example.
I ran the program on Linux. There I had to make sure that helloworld.exe was on my
path and I changed the command to ./helloworld.exe. I didn't create the sub-directory
called files as in your example.
The character to separate directories in Qt is the slash /. There are special functions to convert between the Qt-style and the native-style, when you want to display something to the user. Internally always make use of slashes. This even works for Windows programs (many console commands can cope with a slash instead of a backslash, too).
Adding debug output is really, really valuable during development. If the Makefile is
not set up correctly or something breaks, the helloworld.exe might end up in a directory, where it is not expected. Thus, I added code to wait for some time until the process has finished. This does not hurt because helloworld.exe needs just some milliseconds to run. Afterwards, I print the error code of QProcess just to be sure that the program has been found and could be executed. So I can be sure that the executable is on my path, that the executable flag is set, that I have permissions for executing the file etc.
I don't know exactly what causes the problem on your machine. However, comparing your solution to mine, having a look at the error code of QProcess and setting break points inside the slots should help you finding the error.

Resources