QTextDocument in thread issue
-
If by passing you mean updating a pointer value, then you are not moving things around.
Since QTextDocument is a QObject, hence the suggestion of using moveToThread.
-
If by passing you mean updating a pointer value, then you are not moving things around.
Since QTextDocument is a QObject, hence the suggestion of using moveToThread.
So, I should call
moveToThread
onQTextDocument object
in a worker or in main GUI? Thanks. -
Since you create it in your secondary thread, you need to push it to your main thread.
-
So, I should call
moveToThread
onQTextDocument object
in a worker or in main GUI? Thanks.@Cobra91151 QTextDocument should not live in a second thread so you get that error. QTextDocument will interact with QObjects that live in the main thread (for example QTextEdit, QPrinter, etc).
-
@Cobra91151 QTextDocument should not live in a second thread so you get that error. QTextDocument will interact with QObjects that live in the main thread (for example QTextEdit, QPrinter, etc).
From this old post, I can use
QTextDocument
object in worker class (second thread) and pass it between the threads: https://www.qt.io/blog/2007/09/27/multi-threaded-text-layout-and-printingIt contains the old thread design but I want to check out the full source code. Where I can find this snapshot example? Thank you.
-
Based on the name, I would go with the Qt 4 sources of Assistant.
-
@Cobra91151 QTextDocument should not live in a second thread so you get that error. QTextDocument will interact with QObjects that live in the main thread (for example QTextEdit, QPrinter, etc).
@eyllanesc said in QTextDocument in thread issue:
@Cobra91151 QTextDocument should not live in a second thread so you get that error. QTextDocument will interact with QObjects that live in the main thread (for example QTextEdit, QPrinter, etc).
I had
QTextDocument
in my main thread butsetPlainText
method freezes theGUI
for a couple of seconds. So, I need to fix it. That is why I put it to the worker (second thread). Thanks. -
@eyllanesc said in QTextDocument in thread issue:
@Cobra91151 QTextDocument should not live in a second thread so you get that error. QTextDocument will interact with QObjects that live in the main thread (for example QTextEdit, QPrinter, etc).
I had
QTextDocument
in my main thread butsetPlainText
method freezes theGUI
for a couple of seconds. So, I need to fix it. That is why I put it to the worker (second thread). Thanks.@Cobra91151 Qt UI classes should not be used in other threads than main (UI) thread!
How big is the text you're trying to load? -
@Cobra91151 Qt UI classes should not be used in other threads than main (UI) thread!
How big is the text you're trying to load?It is 280 pages for printing. I run some debugging and found out that
setPlainText
does not lead to such issue. The actual problem is withprint
method. It takes too much time to paint all these pages to theQPrintPreviewDialog
.Code:
connect(printPreviewDlg, &QPrintPreviewDialog::paintRequested, this, [txtDoc](QPrinter *printer) { txtDoc->print(printer); });
I will subclass the
QTextDocument
and reimplement theprint
method to display some progress dialog. Thanks. -
Nope, it does not work. The progress dialog still freezing.
-
Nope, it does not work. The progress dialog still freezing.
@Cobra91151 Can you show ther code?
-
@Cobra91151 Can you show ther code?
Yes, I will create the test example and post it soon. Thank you.
-
Yes, I will create the test example and post it soon. Thank you.
@Cobra91151
Also for 280 pages just how long does it take/freeze? Oh you said "a couple of seconds". Does your end-user not have the patience to wait 2 seconds for 280 pages? :) If the user prints to printer how long does it take? Users are over-pampered these days.... -
@Cobra91151
Also for 280 pages just how long does it take/freeze? Oh you said "a couple of seconds". Does your end-user not have the patience to wait 2 seconds for 280 pages? :) If the user prints to printer how long does it take? Users are over-pampered these days....Here is my test example:
printexample.h
#ifndef PRINTEXAMPLE_H #define PRINTEXAMPLE_H #include <QWidget> #include <QPushButton> #include <QHBoxLayout> #include <QThread> #include <QPrinter> #include <QPrintPreviewDialog> #include <QToolBar> #include <QTextDocument> #include <QDebug> #include "printworker.h" class PrintExample : public QWidget { Q_OBJECT public: PrintExample(QWidget *parent = nullptr); ~PrintExample(); private slots: void printData(); void setPrintPreviewData(QString printData); void setPreviewDataGenerationFailed(); private: QLayout *printLayout(QPushButton *btn); }; #endif // PRINTEXAMPLE_H
printexample.cpp
#include "printexample.h" PrintExample::PrintExample(QWidget *parent) : QWidget(parent) { setWindowTitle("Print example"); setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); setFixedSize(500, 400); QPushButton *printBtn = new QPushButton("Print", this); printBtn->setFixedSize(120, 50); connect(printBtn, &QPushButton::clicked, this, &PrintExample::printData); setLayout(printLayout(printBtn)); } QLayout *PrintExample::printLayout(QPushButton *btn) { QHBoxLayout *btnLayout = new QHBoxLayout(); btnLayout->setAlignment(Qt::AlignHCenter); btnLayout->addWidget(btn); return btnLayout; } void PrintExample::printData() { //This is just test example data QString testBigData = "QTextDocument is a container for structured rich text documents, providing support for styled text and various types of document elements, such as lists, tables, " "frames, and images. They can be created for use in a QTextEdit, or used independently. Each document element is described by an associated format object. " "Each format object is treated as a unique object by QTextDocuments, and can be passed to objectForFormat() to obtain the document element that it is applied to. " "A QTextDocument can be edited programmatically using a QTextCursor, and its contents can be examined by traversing the document structure. " "The entire document structure is stored as a hierarchy of document elements beneath the root frame, found with the rootFrame() function. " "Alternatively, if you just want to iterate over the textual contents of the document you can use begin(), end(), and findBlock() to retrieve text blocks that you can " "examine and iterate over. The layout of a document is determined by the documentLayout(); you can create your own QAbstractTextDocumentLayout subclass and set it using " "setDocumentLayout() if you want to use your own layout logic. The document's title and other meta-information can be obtained by calling the metaInformation() " "function. For documents that are exposed to users through the QTextEdit class, the document title is also available via the QTextEdit::documentTitle() " "function. The toPlainText() and toHtml() convenience functions allow you to retrieve the contents of the document as plain text and HTML. " "The document's text can be searched using the find() functions. Undo/redo of operations performed on the document can be controlled using the setUndoRedoEnabled() " "function. The undo/redo system can be controlled by an editor widget through the undo() and redo() slots; the document also provides contentsChanged(), " "undoAvailable(), and redoAvailable() signals that inform connected editor widgets about the state of the undo/redo system. " "The following are the undo/redo operations of a QTextDocument."; QThread *printDataThread = new QThread(); PrintWorker *printWorker = new PrintWorker(); printWorker->moveToThread(printDataThread); connect(printWorker, &PrintWorker::generatedPreviewData, this, &PrintExample::setPrintPreviewData); connect(printWorker, &PrintWorker::previewDataGenerationFailed, this, &PrintExample::setPreviewDataGenerationFailed); connect(printWorker, &PrintWorker::finished, printDataThread, &QThread::quit); connect(printWorker, &PrintWorker::finished, printWorker, &PrintWorker::deleteLater); connect(printDataThread, &QThread::finished, printDataThread, &QThread::deleteLater); QMetaObject::invokeMethod(printWorker, "generatePrintPreview", Q_ARG(QString, testBigData)); printDataThread->start(); } void PrintExample::setPrintPreviewData(QString printData) { QPrinter *previewPrinter = new QPrinter(QPrinter::HighResolution); previewPrinter->setOutputFormat(QPrinter::NativeFormat); previewPrinter->setPaperSize(QPrinter::A4); previewPrinter->setPageMargins(QMarginsF(15, 15, 15, 15)); QPrintPreviewDialog *printPreviewDlg = new QPrintPreviewDialog(previewPrinter, this); printPreviewDlg->setGeometry(100, 100, 700, 500); printPreviewDlg->setMinimumSize(700, 500); printPreviewDlg->setWindowModality(Qt::ApplicationModal); printPreviewDlg->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); printPreviewDlg->installEventFilter(this); QFont docFont; docFont.setPointSize(14); QTextDocument *textDoc = new QTextDocument(this); textDoc->setDefaultFont(docFont); textDoc->setPlainText(printData); connect(printPreviewDlg, &QPrintPreviewDialog::paintRequested, this, [this, textDoc](QPrinter *printer) { textDoc->print(printer); }); connect(printPreviewDlg, &QPrintPreviewDialog::finished, this, [textDoc, previewPrinter, printPreviewDlg]() { textDoc->deleteLater(); delete previewPrinter; printPreviewDlg->deleteLater(); }); printPreviewDlg->show(); } void PrintExample::setPreviewDataGenerationFailed() { //Failed to generate preview } PrintExample::~PrintExample() { }
printworker.h:
#ifndef PRINTWORKER_H #define PRINTWORKER_H #include <QObject> class PrintWorker : public QObject { Q_OBJECT public: explicit PrintWorker(QObject *parent = nullptr); public slots: void generatePrintPreview(QString previewData); signals: void generatedPreviewData(QString data); void previewDataGenerationFailed(); void finished(); }; #endif // PRINTWORKER_H
printworker.cpp:
#include "printworker.h" PrintWorker::PrintWorker(QObject *parent) : QObject(parent) { } void PrintWorker::generatePrintPreview(QString previewData) { if (!previewData.isEmpty()) { emit generatedPreviewData(previewData); } else { emit previewDataGenerationFailed(); } emit finished(); }
Screenshot:
So, it does not freeze much for 1 page. Anyway, I want to display some progress dialog before the preview dialog. Any ideas? Thanks.
-
Here is my test example:
printexample.h
#ifndef PRINTEXAMPLE_H #define PRINTEXAMPLE_H #include <QWidget> #include <QPushButton> #include <QHBoxLayout> #include <QThread> #include <QPrinter> #include <QPrintPreviewDialog> #include <QToolBar> #include <QTextDocument> #include <QDebug> #include "printworker.h" class PrintExample : public QWidget { Q_OBJECT public: PrintExample(QWidget *parent = nullptr); ~PrintExample(); private slots: void printData(); void setPrintPreviewData(QString printData); void setPreviewDataGenerationFailed(); private: QLayout *printLayout(QPushButton *btn); }; #endif // PRINTEXAMPLE_H
printexample.cpp
#include "printexample.h" PrintExample::PrintExample(QWidget *parent) : QWidget(parent) { setWindowTitle("Print example"); setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); setFixedSize(500, 400); QPushButton *printBtn = new QPushButton("Print", this); printBtn->setFixedSize(120, 50); connect(printBtn, &QPushButton::clicked, this, &PrintExample::printData); setLayout(printLayout(printBtn)); } QLayout *PrintExample::printLayout(QPushButton *btn) { QHBoxLayout *btnLayout = new QHBoxLayout(); btnLayout->setAlignment(Qt::AlignHCenter); btnLayout->addWidget(btn); return btnLayout; } void PrintExample::printData() { //This is just test example data QString testBigData = "QTextDocument is a container for structured rich text documents, providing support for styled text and various types of document elements, such as lists, tables, " "frames, and images. They can be created for use in a QTextEdit, or used independently. Each document element is described by an associated format object. " "Each format object is treated as a unique object by QTextDocuments, and can be passed to objectForFormat() to obtain the document element that it is applied to. " "A QTextDocument can be edited programmatically using a QTextCursor, and its contents can be examined by traversing the document structure. " "The entire document structure is stored as a hierarchy of document elements beneath the root frame, found with the rootFrame() function. " "Alternatively, if you just want to iterate over the textual contents of the document you can use begin(), end(), and findBlock() to retrieve text blocks that you can " "examine and iterate over. The layout of a document is determined by the documentLayout(); you can create your own QAbstractTextDocumentLayout subclass and set it using " "setDocumentLayout() if you want to use your own layout logic. The document's title and other meta-information can be obtained by calling the metaInformation() " "function. For documents that are exposed to users through the QTextEdit class, the document title is also available via the QTextEdit::documentTitle() " "function. The toPlainText() and toHtml() convenience functions allow you to retrieve the contents of the document as plain text and HTML. " "The document's text can be searched using the find() functions. Undo/redo of operations performed on the document can be controlled using the setUndoRedoEnabled() " "function. The undo/redo system can be controlled by an editor widget through the undo() and redo() slots; the document also provides contentsChanged(), " "undoAvailable(), and redoAvailable() signals that inform connected editor widgets about the state of the undo/redo system. " "The following are the undo/redo operations of a QTextDocument."; QThread *printDataThread = new QThread(); PrintWorker *printWorker = new PrintWorker(); printWorker->moveToThread(printDataThread); connect(printWorker, &PrintWorker::generatedPreviewData, this, &PrintExample::setPrintPreviewData); connect(printWorker, &PrintWorker::previewDataGenerationFailed, this, &PrintExample::setPreviewDataGenerationFailed); connect(printWorker, &PrintWorker::finished, printDataThread, &QThread::quit); connect(printWorker, &PrintWorker::finished, printWorker, &PrintWorker::deleteLater); connect(printDataThread, &QThread::finished, printDataThread, &QThread::deleteLater); QMetaObject::invokeMethod(printWorker, "generatePrintPreview", Q_ARG(QString, testBigData)); printDataThread->start(); } void PrintExample::setPrintPreviewData(QString printData) { QPrinter *previewPrinter = new QPrinter(QPrinter::HighResolution); previewPrinter->setOutputFormat(QPrinter::NativeFormat); previewPrinter->setPaperSize(QPrinter::A4); previewPrinter->setPageMargins(QMarginsF(15, 15, 15, 15)); QPrintPreviewDialog *printPreviewDlg = new QPrintPreviewDialog(previewPrinter, this); printPreviewDlg->setGeometry(100, 100, 700, 500); printPreviewDlg->setMinimumSize(700, 500); printPreviewDlg->setWindowModality(Qt::ApplicationModal); printPreviewDlg->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); printPreviewDlg->installEventFilter(this); QFont docFont; docFont.setPointSize(14); QTextDocument *textDoc = new QTextDocument(this); textDoc->setDefaultFont(docFont); textDoc->setPlainText(printData); connect(printPreviewDlg, &QPrintPreviewDialog::paintRequested, this, [this, textDoc](QPrinter *printer) { textDoc->print(printer); }); connect(printPreviewDlg, &QPrintPreviewDialog::finished, this, [textDoc, previewPrinter, printPreviewDlg]() { textDoc->deleteLater(); delete previewPrinter; printPreviewDlg->deleteLater(); }); printPreviewDlg->show(); } void PrintExample::setPreviewDataGenerationFailed() { //Failed to generate preview } PrintExample::~PrintExample() { }
printworker.h:
#ifndef PRINTWORKER_H #define PRINTWORKER_H #include <QObject> class PrintWorker : public QObject { Q_OBJECT public: explicit PrintWorker(QObject *parent = nullptr); public slots: void generatePrintPreview(QString previewData); signals: void generatedPreviewData(QString data); void previewDataGenerationFailed(); void finished(); }; #endif // PRINTWORKER_H
printworker.cpp:
#include "printworker.h" PrintWorker::PrintWorker(QObject *parent) : QObject(parent) { } void PrintWorker::generatePrintPreview(QString previewData) { if (!previewData.isEmpty()) { emit generatedPreviewData(previewData); } else { emit previewDataGenerationFailed(); } emit finished(); }
Screenshot:
So, it does not freeze much for 1 page. Anyway, I want to display some progress dialog before the preview dialog. Any ideas? Thanks.
@Cobra91151 I'm not sure there is an easy way to add a progress dialog here as printing does not emit any signals reporting progress as far as I know. But you could have a busy indicator to let the user know that the app is busy. Would that be enough?
-
@Cobra91151 I'm not sure there is an easy way to add a progress dialog here as printing does not emit any signals reporting progress as far as I know. But you could have a busy indicator to let the user know that the app is busy. Would that be enough?
Yes, it should work well too. Thanks.