First of all, you don't have any multithreading in your app at all. Your FileReader
class is a subclass of QThread
, but it does not mean that all FileReader
methods will be executed in another thread. In fact, all your operations are performed in the main (GUI) thread.
FileReader
should be a QObject
and not a QThread
subclass. Then you create a basic QThread
object and move your worker (reader) to it using QObject::moveToThread
. You can read about this technique here.
Make sure you have registered FileReader::State
type using qRegisterMetaType
. This is necessary for Qt signal-slot connections to work across different threads.
An example:
HexViewer::HexViewer(QWidget *parent) :
QMainWindow(parent),
_ui(new Ui::HexViewer),
_fileReader(new FileReader())
{
qRegisterMetaType<FileReader::State>("FileReader::State");
QThread *readerThread = new QThread(this);
readerThread->setObjectName("ReaderThread");
connect(readerThread, SIGNAL(finished()),
_fileReader, SLOT(deleteLater()));
_fileReader->moveToThread(readerThread);
readerThread->start();
_ui->setupUi(this);
...
}
void HexViewer::on_quitButton_clicked()
{
_fileReader->thread()->quit();
_fileReader->thread()->wait();
qApp->quit();
}
Also it is not necessary to allocate data on the heap here:
while(!inFile.atEnd())
{
QByteArray *qa = new QByteArray(inFile.read(DATA_SIZE));
qDebug() << "emitting dataRead()";
emit dataRead(qa);
}
QByteArray
uses implicit sharing. It means that its contents are not copied again and again when you pass a QByteArray
object across functions in a read-only mode.
Change the code above to this and forget about manual memory management:
while(!inFile.atEnd())
{
QByteArray qa = inFile.read(DATA_SIZE);
qDebug() << "emitting dataRead()";
emit dataRead(qa);
}
But anyway, the main problem is not with multithreading. The problem is that QTextEdit::insertPlainText
operation is not cheap, especially when you have a huge amount of data. FileReader
reads file data pretty quickly and then floods your widget with new portions of data to display.
It must be noted that you have a very ineffectual implementation of HexViewer::loadData
. You insert text data char by char which makes QTextEdit
constantly redraw its contents and freezes the GUI.
You should prepare the resulting hex string first (note that data parameter is not a pointer anymore):
void HexViewer::loadData(QByteArray data)
{
QString tmp = data.toHex();
QString hexString;
hexString.reserve(tmp.size() * 1.5);
const int hexLen = 2;
for (int i = 0; i < tmp.size(); i += hexLen)
{
hexString.append(tmp.mid(i, hexLen) + " ");
}
_ui->hexTextView->insertPlainText(hexString);
}
Anyway, the bottleneck of your application is not file reading but QTextEdit
updating. Loading data by chunks and then appending it to the widget using QTextEdit::insertPlainText
will not speed up anything. For files less than 1Mb it is faster to read the whole file at once and then set the resulting text to the widget in a single step.
I suppose you can't easily display huge texts larger than several megabytes using default Qt widgets. This task requires some non-trivial approch that in general has nothing to do with multithreading or asynchronous data loading. It's all about creating some tricky widget which won't try to display its huge contents at once.