Displaying a Large PDF without Freezing the UI Thread
-
Hi everyone,
I am having some problems displaying a large PDF file using a Loader. I have a sample code below:
When the Load button is pressed in the code below, a large PDF file is displayed using PdfMultiPageView. I also make an AnimatedImage visible when the Loader is loading the component. However, since the PDF is a large file, the UI thread probably freezes when creating the PDF elements.
Do you have any suggestions for cases like this?
I am aware that using Qt.callLater is useful for operations with loops that take a long time, but this case is a little bit different.
Thanks in advance.
import QtQuick import QtQuick.Pdf import QtQuick.Controls Window { width: 500 height: 500 visible: true title: "PdfTest" Rectangle { anchors.fill:parent Loader{ id: loader anchors.fill: parent asynchronous: true sourceComponent: undefined onLoaded: loadingImg.visible = false } Component{ id: pmvComp PdfMultiPageView{ document: PdfDocument{ source: 'LARGE_PDF_FILE.pdf'} // some Pdf with 20 MB size } } AnimatedImage { id: loadingImg anchors.centerIn: parent source: "loading.gif" width:50 height:50 visible:false } Button{ anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom anchors.bottomMargin: 10 text: loader.sourceComponent == undefined ? "Load":"Unload" onClicked: { if(loader.sourceComponent == undefined){ loadingImg.visible = true loader.sourceComponent = pmvComp } else{ loader.sourceComponent = undefined } } } } } -
Hey, can someone please reply to this? I'm trying to load a PDF in a Qt Widget application using threading. Irrespective of what I do, it fails to load the PDF. I tried creating a concurrent thread, made a new QPdfDocument, loaded a PDF into the entity and then moved it to the main thread before returning the pointer. It still doesn't work! Here is an MWE (I know that the PDF loading in this example is synchronous, but even this fails to work - forget about loading the PDF asynchronously):
QFuture<QPdfDocument*> future = QtConcurrent::run([](){ QPdfDocument* loadDoc = new QPdfDocument(); loadDoc->load(ProjectSettings::instance().pdfPath); loadDoc->moveToThread(QApplication::instance()->thread()); return loadDoc; }); m_document = future.result(); -
Hey, can someone please reply to this? I'm trying to load a PDF in a Qt Widget application using threading. Irrespective of what I do, it fails to load the PDF. I tried creating a concurrent thread, made a new QPdfDocument, loaded a PDF into the entity and then moved it to the main thread before returning the pointer. It still doesn't work! Here is an MWE (I know that the PDF loading in this example is synchronous, but even this fails to work - forget about loading the PDF asynchronously):
QFuture<QPdfDocument*> future = QtConcurrent::run([](){ QPdfDocument* loadDoc = new QPdfDocument(); loadDoc->load(ProjectSettings::instance().pdfPath); loadDoc->moveToThread(QApplication::instance()->thread()); return loadDoc; }); m_document = future.result();@Bubu-Droid
Obviously to start with:- QPdfDocument::Error QPdfDocument::error() const (and statusChanged(QPdfDocument::Status status)). This is vital and first thing you should check.
- Verify
ProjectSettings::instance().pdfPathexists. - Have you tried multiple/absolute minimal PDF documents?
- Get rid of any concurrency/moveToThread.
- Is it safe/sensible to call
loadDoc->moveToThread()whileloadDoc->load()is running? Even if it is allowed, why/what is the effect of setting off a load before moving to a thread?
-
@Bubu-Droid
Obviously to start with:- QPdfDocument::Error QPdfDocument::error() const (and statusChanged(QPdfDocument::Status status)). This is vital and first thing you should check.
- Verify
ProjectSettings::instance().pdfPathexists. - Have you tried multiple/absolute minimal PDF documents?
- Get rid of any concurrency/moveToThread.
- Is it safe/sensible to call
loadDoc->moveToThread()whileloadDoc->load()is running? Even if it is allowed, why/what is the effect of setting off a load before moving to a thread?
The PDF path does exist. I've removed the entire threading logic and I'm currently trying to load the PDF document in the main thread. I tried adding a print statement just after
pdfDocument->load()for debugging purposes and noticed that the statement gets printed immediately even though the PDF has not finished loading yet and the UI is frozen.What I want to avoid is the freezing of UI when I'm trying to load a large PDF. I'm using X11 as my display server.
The pdfviewer project in Qt examples has the same problem. The UI freezes when I'm trying to load a large PDF.
qDebug() << ProjectSettings::instance().pdfDocument->status();I added this after the
load()statement to check what the result is. It's weird that this returnsREADYeven though the UI remains frozen. -
The PDF path does exist. I've removed the entire threading logic and I'm currently trying to load the PDF document in the main thread. I tried adding a print statement just after
pdfDocument->load()for debugging purposes and noticed that the statement gets printed immediately even though the PDF has not finished loading yet and the UI is frozen.What I want to avoid is the freezing of UI when I'm trying to load a large PDF. I'm using X11 as my display server.
The pdfviewer project in Qt examples has the same problem. The UI freezes when I'm trying to load a large PDF.
qDebug() << ProjectSettings::instance().pdfDocument->status();I added this after the
load()statement to check what the result is. It's weird that this returnsREADYeven though the UI remains frozen.@Bubu-Droid
Initially you wroteit fails to load the PDF
Now you say
What I want to avoid is the freezing of UI when I'm trying to load a large PDF
Which is the case? Does it fail to load the PDF and you should be looking at
error()or does it take rather longer than you want and possibly interfere with UI's responsiveness but if you went and made a coffee it would complete by the time you returned? These are two very different situations. -
The PDF path does exist. I've removed the entire threading logic and I'm currently trying to load the PDF document in the main thread. I tried adding a print statement just after
pdfDocument->load()for debugging purposes and noticed that the statement gets printed immediately even though the PDF has not finished loading yet and the UI is frozen.What I want to avoid is the freezing of UI when I'm trying to load a large PDF. I'm using X11 as my display server.
The pdfviewer project in Qt examples has the same problem. The UI freezes when I'm trying to load a large PDF.
qDebug() << ProjectSettings::instance().pdfDocument->status();I added this after the
load()statement to check what the result is. It's weird that this returnsREADYeven though the UI remains frozen.@Bubu-Droid said in Displaying a Large PDF without Freezing the UI Thread:
qDebug() << ProjectSettings::instance().pdfDocument->status();
I added this after the load() statement to check what the result is. It's weird that this returns READY even though the UI remains frozen.
You just added this.
load()is asynchronous. You should start by placing a slot on statusChanged(QPdfDocument::Status status) to see what is happening. Does that show loading and then ready or error or never gets to either? -
@Bubu-Droid said in Displaying a Large PDF without Freezing the UI Thread:
qDebug() << ProjectSettings::instance().pdfDocument->status();
I added this after the load() statement to check what the result is. It's weird that this returns READY even though the UI remains frozen.
You just added this.
load()is asynchronous. You should start by placing a slot on statusChanged(QPdfDocument::Status status) to see what is happening. Does that show loading and then ready or error or never gets to either?Hey, I've figured out the cause. It's being caused by the thumbnail rendering. I commented out the line
ui->thumbnailView->setModel(pdfDocument->pageModel());and the PDF is loaded instantly.
Maybe loading the thumbnails on a different thread won't freeze the UI?(setModel isn't thread safe it seems). ThesetModelprobably causing problems since thepdfDocument->pageModel()is huge. Can you please help me out with how I could fix this? ThethumbnailViewis aQListViewbtw.EDIT: I've set
setUniformItemSizesto true and the loading is much faster now (almost instantaneous).ui->thumbnailView->setUniformItemSizes(true);I think this was the key to making the view load its items faster. But the scrolling in the
thumbnailViewwidget is pretty laggy.