Search code examples
qt

Nice text formatting in QTextEdit, like Qt Creator does


Qt Creator spots a nice formatting operation, drawing a thin frame around some text (here an example, I refer to the frames around addRow, the yellow areas were the result a text find operation that also had framed the locations found, before I moved the cursor..)

Enter image description here

I've been unable to find how to get that effect in QTextEdit. I tried to read from Qt Creator sources, but they are too large for uninformed search...

edit

I started just now to look into custom QTextCharAttribute, via

class framedTextAttr : public QTextObjectInterface {...}

edit

It's working: as per my answer below.


Solution

  • With QTextObjectInterface I get the frame around the text object:

    QSizeF framedTextAttr::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format)
    {
        Q_ASSERT(format.type() == format.CharFormat);
        const QTextCharFormat &tf = *(const QTextCharFormat*)(&format);
        QString s = format.property(prop()).toString();
        QFont fn = tf.font();
        QFontMetrics fm(fn);
        return fm.boundingRect(s).size();
    }
    
    void framedTextAttr::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format)
    {
        Q_ASSERT(format.type() == format.CharFormat);
        QString s = format.property(prop()).toString();
        painter->drawText(rect, s);
        painter->drawRoundedRect(rect, 2, 2);
    }
    

    But the text becomes a single object, no more editable

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        setCentralWidget(new QTextEdit);
    
        framedTextAttr *fa = new framedTextAttr;
        editor()->document()->documentLayout()->registerHandler(framedTextAttr::type(), fa);
    
        editor()->setPlainText("hic sunt\n leones !");
    
        QTextCharFormat f;
        f.setObjectType(fa->type());
    
        QTextCursor c = editor()->document()->find("leones");
        f.setProperty(fa->prop(), c.selectedText());
    
        c.insertText(QString(QChar::ObjectReplacementCharacter), f);
    }
    

    And the result (here a picture):

    Enter image description here

    It seems it's difficult to generalize. I'm not satisfied...

    edit

    Actually, it's feasible. I've worked out some of the problems with the illustrated approach, and it seems to be viable also for folding/unfolding text in reusable fashion.

    Enter image description here

    I've put my test project on GitHub.