QPainter::drawText, get bounding boxes for each character

核能气质少年 提交于 2019-12-10 10:08:22

问题


I'm using QPainter to draw multiline text on QImage. However, I also need to display a colored rectangle around each character's bounding box.

So I need to know the bounding box that each character had when being drawn.

For example, for

painter.drawText(QRect(100, 100, 200, 200), Qt::TextWordWrap, "line\nline2", &r);

I would need to get 10 rectangles, taking into account newlines, word-wrap, tabs, etc.

For example, the rectangle of the second 'l' would be below the rectangle of the first 'l', instead of being to the right of 'e', because of the newline.

Something like the coordinates of the red rectangles in this picture (I've put them by hand so they're not really the correct positions):


回答1:


This may not be the best solution, but it's the best one I can think of.

I believe you will have to "do it yourself". That is, instead of drawing a block of text, draw each character one at a time. Then you can use QFontMetrics to get the bounding box of each character.

It's a little work, but not too bad. Something like (pseudo code, not code):

QFontMetrics fm(myFont, paintDevice);
int x = startX;
int y = startY;
for (unsigned int i = 0; i < numChars; i++)
{
    char myChar = mystr[i];  // get character to print/bound
    QRect rect = fm.boundingRect( myChar );   // get that char's bounding box
    painter.drawText(x, y, Qt::TextWordWrap, mystr[i], &r);  // output char
    painter.drawRect(...); // draw char's bounding box using 'rect'
    x += rect.width();     // advance current position horizontally

    // TODO:
    // if y > lineLen      // handle cr
    //     x = startX;
    //     y += line height

}

Check out QFontMetrics, it has a number of different methods for getting bounding boxes, minimum bounding boxes, etc.

QFontMetrics 4.7

Ahhh... I see now that the overload you're using returns the actual bounding rect. You can just use that and skip the QFontMetrics if you like - otherwise the overall algorithm is the same.




回答2:


You can retrieve the bounding boxes of individual characters with QFontMetrics::boundingRect(QChar), but they have to be rendered at an offset (QFontMetrics::ascent from the top as well as QFontMetrics::width of the preceding characters from the left) because they are relative to the font’s base line and not to the bottom of the bounding box of the complete string.
Several lines also have to be handled separately. QFontMetrics::lineSpacing give you their offset.

QPainter painter(this);
painter.setFont(QFont("Arial", 72));

auto pen = painter.pen();

QString text{"line\nline2\ngg\n`"};
QRect boundingRect;
painter.drawText(rect(), Qt::AlignLeft | Qt::AlignTop, text, &boundingRect);
painter.drawRect(boundingRect.adjusted(0, 0, -pen.width(), -pen.width()));

pen.setColor(Qt::red);
painter.setPen(pen);
const auto lines = text.split('\n');
const auto fm = painter.fontMetrics();
for (int linei = 0; linei < lines.size(); ++linei) {
    const auto & line = lines[linei];
    for (int chi = 0; chi < line.size(); ++chi) {
        const auto bounds = fm.boundingRect(line[chi]);
        const auto xoffset = bounds.x() + fm.width(line, chi);
        const auto lineOffset = linei * fm.lineSpacing() + fm.ascent();
        const auto yoffset = lineOffset + bounds.y();
        painter.drawRect(QRect{xoffset, yoffset, bounds.width(), bounds.height()});
    }
}

results in

which, sadly – isn’t perfect though.



来源:https://stackoverflow.com/questions/13364231/qpainterdrawtext-get-bounding-boxes-for-each-character

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!