Search code examples
qtrichtextqgraphicstextitem

Reading Rich Text Character and Block Formatting


I have rich text items implemented using QGraphicsTextItem

To set font size, for example:

void set (int fontSize) { 
    QTextCursor _cursor = textCursor();
    QTextCharFormat _format;
    _format.setFontPointSize(fontSize);
    _cursor.mergeCharFormat(_format);
    setTextCursor(_cursor); }

A lot more complicated is to read the font size.
Assuming I have a selection, I must iterate through the document, through all QTextBlock, QTextFragment, reading the QTextCharFormat ...
But the simple option, if there is no selection, just reading the font size at cursor:

int get () {
    return textCursor().charFormat().fontPointSize(); }

This works, but I found 3 issues:

1) Setting font size by QGraphicsTextItem properties:

QFont f = font();
f.setPointSize(20);
setFont(f);

this returns 0 by my get function above. To set the font size for the entire item, I have to use the same method as in the set function.
Shouldn't the setFont method set a font that can be read from the QTextCursor ?

2) setHtml can set formatting - but I don't see any way to read that formatting
How can I read the rich text formatting from an html fragment ? Is the only posiblity, parsing the html ?

3) (my current stumbling block)
Copy formatted text from an outside source and paste in the QGraphicsTextItem seems to maintain the formatting of the source - but how can I read that formatting ?
The get method above reads font size 0 if the text was pasted from outside.
font().pointSize() always returns 8. (I have not set it so I imagine that is a default)
Is there another method to read the text format ?
is the clipboard text formatted using html ?

How can I find the font size (or any other formatting) from the pasted text ?

(The same questions apply to block formatting, like alignment).


Solution

  • I think most of your problems could be solved by getting the QTextDocument for your QGraphicsTextItem object and work with it. QTextDocument and its methods (like QTextFormat::property(int propertyId)) can help you to get a lot of properties for your text.

    1) If you set the size using the QFont object, you should get the size using the same way.

    2) When you set the text using html, QGraphicsTextItem::font() is not useful so you need to get the QTextDocument and use their functions instead.

    3) Same as 2. I think... because I don't have your code to test it :)

    Well, here you have a code as an example. I hope this answer helps you.

    #include <QApplication>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QGraphicsTextItem>
    #include <QTextCursor>
    #include <QTextCharFormat>
    #include <QFont>
    #include <QDebug>
    #include <QTextDocument>
    #include <QTextBlock>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QGraphicsScene scene;
        QGraphicsView view(&scene);
    
        /* ITEM 1 */
        QGraphicsTextItem* item_1  = new QGraphicsTextItem("QGraphicsTextItem 1");
        item_1->setTextInteractionFlags(Qt::TextEditorInteraction);
        QFont f = item_1->font();
        f.setPointSize(30);
        item_1->setFont(f);
    
        qDebug() << "textCursor().position() (returns 0): " <<
                    item_1->textCursor().position();
        qDebug() << "textCursor().charFormat().fontPointSize() (returns 0): " <<
                    item_1->textCursor().charFormat().fontPointSize();
        qDebug() << "font().pointSize() (returns 30 - OK!): " <<
                    item_1->font().pointSize();
    
        QTextDocument* doc = item_1->document();
        f = doc->defaultFont();
        qDebug() << "pointSize (returns 30 - OK!): " << f.pointSize();
    
        scene.addItem(item_1);
    
        /* ITEM 2 */
        QGraphicsTextItem* item_2  = new QGraphicsTextItem();
        item_2->setPos(0, 50);
        item_2->setHtml("<html><head/><body><p>"
                        "<span style=\"font-size:14pt; font-weight:600;\">QGraphics</span>"
                        "<span style=\"font-size:24pt; font-weight:600;\">TextItem 2</span>"
                        "</p></body></html>");
    
        qDebug() << "font().pointSize() (returns 8, the default value): "
                 << item_2->font().pointSize();
    
        doc = item_2->document();
        f = doc->defaultFont();
        qDebug() << "pointSize (returns 8, the default value): " << f.pointSize();
    
        QVector<QTextFormat> formats = doc->allFormats();
        QVectorIterator<QTextFormat> i(formats);
        while (i.hasNext()) {
            QTextFormat format = i.next();
            if (format.property(QTextFormat::FontPointSize).isValid())
                qDebug() << "format.property (returns 14 or 24): " <<
                            format.property(QTextFormat::FontPointSize).toInt();
        }
    
        /*
         * Get the block of text. In this example, we only have one block, but
         * two text fragments (see below)
         */
        QTextBlock text_block = item_2->document()->findBlock(1);
        QTextBlock::iterator it;
    
        for (it = text_block.begin(); !(it.atEnd()); ++it) {
            QTextFragment currentFragment = it.fragment();
            if (currentFragment.isValid())
                qDebug() << "currentFragment.text(): " << currentFragment.text();
                qDebug() << "currentFragment.charFormat().font().pointSize() "
                            "(returns 14 or 24, depending on"
                            "the current text fragment): " <<
                            currentFragment.charFormat().font().pointSize();
        }
    
        scene.addItem(item_2);
    
        view.setFixedSize(640, 480);
        view.show();
        return a.exec();
    }