1

I am using TextEditor from the example provided with Qt (https://doc.qt.io/qt-5/qtquickcontrols1-texteditor-example.html). Here is the complete code https://code.qt.io/cgit/qt/qtquickcontrols.git/tree/examples/quickcontrols/controls/texteditor?h=5.15

I have created a custom method void DocumentHandler::setBackgroundColor(const QColor &color) to change the background color of the overall HTML document.

My problem is whenever I call a method to change the background color of QTextDocument using setDefaultStyleSheet, it is executed only once. ie, my document background changes only once. For the next calls, I can see the qDebug printing correctly, but the setDefaultStyleSheet doesn't work. However, everything works perfectly with normal text, only not with m_doc->toHtml().

How do I fix this?

If I change m_doc->setHtml("some random text"), it works as required

...

QColor DocumentHandler::backgroundColor() const
{
    return m_backgroundColor;
}

void DocumentHandler::setBackgroundColor(const QColor &color)
{

    m_backgroundColor = color.name(); // QColor variable
    m_doc->setDefaultStyleSheet("body{background-color: '"+ color.name() +"'}"); // m_doc is QTextDocument *
    m_doc->setHtml(m_doc->toHtml());

    qDebug() << "BACKGROUND COLOR CHANGED" << color.name() ;
    emit backgroundColorChanged();
}

In the QML, I have called it like this

...
DocumentHandlerModel {
    id: document
    target: textArea
    cursorPosition: textArea.cursorPosition
    selectionStart: textArea.selectionStart
    selectionEnd: textArea.selectionEnd
    backgroundColor: colorDialog2.color
    onFontFamilyChanged: {
        var index = Qt.fontFamilies().indexOf(document.fontFamily)
        if (index === -1) {
            fontFamilyComboBox.currentIndex = 0
            fontFamilyComboBox.special = true
        } else {
            fontFamilyComboBox.currentIndex = index
            fontFamilyComboBox.special = false
        }
    }
    onError: {
        errorDialog.text = message
        errorDialog.visible = true
    }
}
Chilarai
  • 1,842
  • 2
  • 15
  • 33
  • Does this answer your question: https://stackoverflow.com/a/26249813/5366641? – scopchanov Oct 22 '20 at 11:14
  • @scopchanov, that is for `QLabel`.I coudnot find any such method for `QTextDocument`. You are right I think. I need to somehow refresh it. But don't know the exact way – Chilarai Oct 22 '20 at 11:41
  • 1
    Indeed. The answer is for widgets. `QTextDocument` works differently. I now the cause already. Give me some time to find a solution and I will write you an answer. – scopchanov Oct 22 '20 at 12:32

1 Answers1

1

Cause

The documentation of QTextDocument::setDefaultStyleSheet says:

Note: Changing the default style sheet does not have any effect to the existing content of the document.

You try to overcome this by calling setHtml after setDefaultStyleSheet like that:

m_doc->setHtml(m_doc->toHtml());

However, this does not produce the desired result, because setDefaultStyleSheet actually embeds the background color in the HTML through the bgcolor CSS property.

To test this, add

m_doc->setHtml("<html><body><p>Test</p></body></html>");
qDebug() << m_doc->toHtml();

after

m_doc->setHtml(m_doc->toHtml());

The HTML content of m_doc from <html><body><p>Test</p></body></html>, when tested with #FF00FF, becames:

"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style></head><body style=\" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;\" bgcolor=\"#ff00ff\">\n<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Test</p></body></html>"

Note: Please, notice that assignment: bgcolor=\"#ff00ff\.

So, by writing m_doc->setHtml(m_doc->toHtml()); you effectively return the old color. That is why the color changes only the first time.

By the way, the widget now changes its color, but has lost its content.

Solution

It is hard to find an elegant solution, because in this case markup and styles are not kept separate, as in real HTML and CSS, but the style is embedded by Qt in the markup. The one thing which comes to my mind, is to parse the content of m_doc manually.

Note: Such a solution would be extremely fragile and I advise strongly against it. Maybe instead of using a stylesheet, change the background color by setting up the palette of the widget, which renders the content of the QTextDocument on the screen.

Note: In any case this does not seem like the intended behavior, at least it does not match the description in the documentation, so I would have reported it as a bug to Qt, if I were you.

Example

Here is an example I wrote for you in order to demonstrate the proposed solution:

void DocumentHandler::setBackgroundColor(const QColor &color)
{
    const QString &bgcolor("bgcolor=\"");
    QString html(m_doc->toHtml());
    int n = html.indexOf(bgcolor, html.indexOf("<body"));
    int k = n + bgcolor.length();

    m_doc->setDefaultStyleSheet("body { background-color: '" + color.name() + "' }");

    if (n >= 0)
        html.replace(n + bgcolor.length(), html.mid(k, html.indexOf("\"", n + bgcolor.length()) - k).length(), color.name());

    m_doc->setHtml(html);
    m_backgroundColor = color.name(); // QColor variable

    emit backgroundColorChanged();
}
scopchanov
  • 7,966
  • 10
  • 40
  • 68