I'm new to threading and doing an exercise question where I'm writing a program that creates a list of files in a directory and displays it in a QTableWidget
. It uses a separate thread to do the file finding. I'm not sub-classing from QThread
due to this question. When I run the program and search a directory it works fine the first time and displays the names of the files in the table view as expected. But when I try do it again the QTableView
doesn't update.
While debugging I notice my breakpoints in my fileFinder
class don't get triggered on the second try. It seems like the thread doesn't run again the second time like it does the first and I can't figure out why. I'm pretty sure it's a simple bug that I'm missing. Any help will be apprecaited. The code:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "filefinder.h"
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void addToTable(QString name);
void on_btnBrowse_clicked();
private:
Ui::MainWindow *ui;
QThread workerThread;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//set up tableWidget code here omitted
}
void MainWindow::on_btnBrowse_clicked()
{
//clear tableWidget contents
ui->tableFiles->setRowCount(0);
fileFinder *finder = new fileFinder;
finder->moveToThread(&workerThread);
connect(&workerThread, SIGNAL(started()), finder, SLOT(run())); //execute run() function when worker thread has started
connect(finder, SIGNAL(name(QString)), this, SLOT(addToTable(QString))); //pass names from thread to handler slot
connect(&workerThread, SIGNAL(finished()), finder, SLOT(deleteLater())); //delete thread when done
//get directory
QString dir = QFileDialog::getExistingDirectory(this, "Select Directory", "/home", QFileDialog::ShowDirsOnly);
ui->dirEdit->setText(dir);
//set directory in thread object
finder->setDir(dir);
//start worker thread
workerThread.start();
}
//add each name to tableWidget one at a time
void MainWindow::addToTable(QString name)
{
QTableWidgetItem *fileName = new QTableWidgetItem(name);
int row = ui->tableFiles->rowCount();
ui->tableFiles->insertRow(row);
ui->tableFiles->setItem(row, 0, fileName);
}
MainWindow::~MainWindow()
{
workerThread.quit();
workerThread.wait();
delete ui;
}
filefinder.h
#ifndef FILEFINDER_H
#define FILEFINDER_H
#include <QStringList>
#include <QThread>
class fileFinder : public QObject
{
Q_OBJECT
public:
fileFinder();
void searchDir();
void setDir(QString path);
public slots:
void run();
signals:
void name(QString n);
private:
QStringList files;
QString m_dir;
};
#endif // FILEFINDER_H
filefinder.cpp
#include "filefinder.h"
#include <unistd.h>
#include <QDir>
fileFinder::fileFinder()
{
}
//return list of all files in the directory
void fileFinder::searchDir()
{
QDir dir;
dir.setPath(m_dir);
//get list of file names sorted by name
files = dir.entryList(QDir::Files, QDir::Name);
}
//set the selected directory
void fileFinder::setDir(QString path)
{
m_dir = path;
}
//executed when thread is started
void fileFinder::run()
{
searchDir();
//iterate through list of files and emit names one by one
foreach(QString f, files){
emit(name(f));
usleep(100); //pause inbetween emits
}
}