欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

QGraphicsTextItem添加自定义下划线

程序员文章站 2022-06-01 11:05:32
...

qt中有原生的添加下划线的方式(如下)但这种方式效果可能不是很好.

class XXXXX: public QGraphicsTextItem
{
    QTextCharFormat tcf;
    tcf.setFontUnderline(true);
    tcf.setUnderlineStyle(QTextCharFormat::WaveUnderline);
    tcf.setUnderlineColor(QColor("#ffff00"));
    QTextCursor cursor = textCursor();
    cursor.select(QTextCursor::Document);
    cursor.mergeCharFormat(tcf);
    cursor.clearSelection();
    setTextCursor(cursor);
};

效果如下(黄色波浪线)

QGraphicsTextItem添加自定义下划线

我找了一下好像也不能继承然后添加自定义的下划线类型,所以我目前用的方法是在paint函数种绘制(有其他好办法的话,请大神们赐教啊,拜托了)。

QGraphicsTextItem添加自定义下划线

可以看到一是相比于原生的效果会好一点(还可以更加细致的再去调整)二是从圆或者三角形能看出是跟着字符变化的,主要是因为我不是只用boundingbox的宽度之类的计算的。不过效果有点不好的地方在于,一是选择文本时这些绘制的下划线无法包含在选中文本内,有点影响观感。二是以上图的a为例,最右边的圆和其上方的字母a没有居中对齐,原因下述。

void CTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QTextBlock iterBlock = document()->begin();
    int blockHeight = 0;
    qreal linespace = textCursor().blockFormat().lineHeight();
    while(iterBlock != document()->end())
    {
        QTextLayout* textLayout = iterBlock.layout();
        if(nullptr == textLayout)
        {
            continue;
        }
        int lineCount = textLayout->lineCount();
        for(int i=0; i<lineCount; i++)
        {
            QTextLine text = textLayout->lineAt(i);
            if(1 == decType)
            {
                painter->setBrush(Qt::NoBrush);
                QPainterPath path = wavePath(&text,i+1,blockHeight);
                painter->drawPath(path);
            }
            else if(2 == decType)
            {
                QPainterPath lineP = linePath(&text,i+1,blockHeight);
                painter->drawPath(lineP);
            }
            else if(3 == decType)
            {
                QPainterPath doublelineP = doublelinePath(&text,i+1,blockHeight,DoubleLineOffset);
                painter->drawPath(doublelineP);
            }
            else if(4 == decType)
            {
                drawCircle(&text,painter,i+1,blockHeight,9,4);
            }
            else if(5 == decType)
            {
                painter->setBrush(QColor(230,0,0));
                QPainterPath triangleP = trianglePath(&text,i+1,blockHeight,14);
                painter->drawPath(triangleP);
            }
        }
        blockHeight += textLayout->boundingRect().height() + linespace;
        iterBlock = iterBlock.next();
    }
}

void CTextItem::drawCircle(QTextLine* textline, QPainter *painter, const int& lineIndex, const int& blockHeight, int radius, int spacing)
{
    QList<QGlyphRun> listGR = textline->glyphRuns();
    for(int j=0; j<listGR.count(); j++)
    {
        QGlyphRun glr = listGR.at(j);
        QVector<QPointF> pos = glr.positions();
        QPainterPath outPath;
        QVector<QPointF> vecCircle;
        for(int i=0; i<pos.count(); i++)
        {
            double nextX = 0;
            double xPos = pos.at(i).x();
            if(i+1<pos.count())
            {
                nextX = pos.at(i+1).x();
                double diff = nextX - xPos;
                if(diff>=2*radius + 2)
                {
                    xPos += ((diff-2*radius)/2);//调整圆的位置使之与字符居中对齐
                }
            }
            QTextFrame* rootFrame = document()->rootFrame();
            QTextFrameFormat ffmt = rootFrame->frameFormat();
            xPos += ffmt.leftMargin();
            double yPos = lineIndex*textline->height()+ffmt.topMargin()+blockHeight;
            QPointF newP(xPos,yPos);
            vecCircle.append(newP);
            QPainterPath outCircle = circularPath(newP,radius,0);
            outPath.addPath(outCircle);
        }
        QPen tmp_pen;
        tmp_pen.setColor(QColor(230,0,0));
        tmp_pen.setWidth(1);
        painter->setPen(tmp_pen);
        painter->setBrush(Qt::NoBrush);
        painter->drawPath(outPath);

        painter->setBrush(QColor(230,0,0));
        QPainterPath inPath;
        for(int i=0; i<vecCircle.count(); i++)
        {
            QPainterPath inCircle = circularPath(vecCircle.at(i),radius-spacing,spacing);
            inPath.addPath(inCircle);
        }
        painter->drawPath(inPath);
    }
}

主要代码在于

    QList<QGlyphRun> listGR = textline->glyphRuns();
    for(int j=0; j<listGR.count(); j++)
    {
        QGlyphRun glr = listGR.at(j);
        QVector<QPointF> pos = glr.positions();

     }

这个就可以获取每个字符的位置,据此可以实现下划线根据字符的多少而变化。但同时这里无法获取字符的宽度,所以我是根据前后两个位置差算宽度的,也因此最后一个字符无法计算(上述最右边的字母a)还请大神们赐教啊。

另外就是再加上行高,边距之类的。大家可以去研究一下QTextBlock、QTextLayout、QTextLine等相关内容。

相关标签: qt