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);
};
效果如下(黄色波浪线)
我找了一下好像也不能继承然后添加自定义的下划线类型,所以我目前用的方法是在paint函数种绘制(有其他好办法的话,请大神们赐教啊,拜托了)。
可以看到一是相比于原生的效果会好一点(还可以更加细致的再去调整)二是从圆或者三角形能看出是跟着字符变化的,主要是因为我不是只用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等相关内容。