QTextObjectInterface with Qml TextEdit (QQuickTextEdit)

1.2k views Asked by At

I registred handler for simple QTextObjectInterface, that draws just 10x10 red rectangle. When i used QTextEdit in normal QWidget app, it worked.
When i used QQuickTextEdit (TextEdit qml component) in Qt Quick app, it doesn't worked (nothing is drawed, but the rectangle in TextEdit is reserved, because when i change cursor position, i notice that there is something, but just empty space, nothing is drawed.
The QTextObjectInterface intrinsicSize method is called (that explains why i see there is empty space 10x10), but the drawObject method isn't.

I did some research and i found that actually the problem is probably here:

QQuickTextEdit.cpp from Qt 5.3.0 sources (line 1821)

QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) {
.
.
.
if (textFrame->firstPosition() > textFrame->lastPosition()
        && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) {
    updateNodeTransform(node, d->document->documentLayout()->frameBoundingRect(textFrame).topLeft());
    const int pos = textFrame->firstPosition() - 1;
    ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout());
    QTextCharFormat format = a->formatAccessor(pos);
    QTextBlock block = textFrame->firstCursorPosition().block();
    node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
    node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
                                  pos, textFrame->frameFormat().position());
    nodeStart = pos;
}

it never reaches the point where node->m_engine->addTextObject is called.
It is because this part of if condition textFrame->firstPosition() > textFrame->lastPosition() is evaluated to false.
I tried std::cout the firstPostion and the lastPosition when i established the context and firstPosition is 0, lastPosition is 1.

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTextDocument>
#include <QQuickTextDocument>
#include <iostream>
#include <QTextCursor>
#include <QTextBlock>
#include <QPainter>
#include <QAbstractTextDocumentLayout>
#include <QTextCharFormat>
#include "qmlcomponentspace.h"
#include <QTextEdit>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    QTextDocument * doc = engine.rootObjects().first()->findChild<QObject *>("editor")->property("textDocument").value<QQuickTextDocument *>()->textDocument();

    QTextCursor cur(doc);

    int objectType = QTextFormat::UserObject + 1000;

    QmlComponentSpace * component = new QmlComponentSpace();

    doc->documentLayout()->registerHandler(objectType, component);

    QTextCharFormat fmt;
    fmt.setObjectType(objectType);
    fmt.setForeground(Qt::red);
    fmt.setBackground(Qt::red);

    cur.movePosition(QTextCursor::End);

    cur.insertText(QString(QChar::ObjectReplacementCharacter), fmt);

    std::cout << "FIRST:" << doc->rootFrame()->firstPosition() << std::endl;
    std::cout << "END:" << doc->rootFrame()->lastPosition() << std::endl;

    return app.exec();
}

What i am missing?

1

There are 1 answers

0
user2366975 On

The documentation says at

http://doc.qt.io/qt-5/qquicktextdocument.html#details

Warning: The QTextDocument provided is used internally by Qt Quick elements to provide text manipulation primitives. You are not allowed to perform any modification of the internal state of the QTextDocument. If you do, the element in question may stop functioning or crash.