QTextDocument in thread issue
-
Since you create it in your secondary thread, you need to push it to your main thread.
-
So, I should call
moveToThreadonQTextDocument objectin 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
QTextDocumentobject 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
QTextDocumentin my main thread butsetPlainTextmethod freezes theGUIfor 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
QTextDocumentin my main thread butsetPlainTextmethod freezes theGUIfor 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
setPlainTextdoes not lead to such issue. The actual problem is withprintmethod. 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
QTextDocumentand reimplement theprintmethod 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_Hprintexample.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_Hprintworker.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_Hprintexample.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_Hprintworker.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.