我正在使用QPainter在QImage上绘制多行文字。但是,我还需要在每个角色的边界框周围显示一个彩色矩形。
所以我需要知道每个角色在绘制时的边界框。
例如,
painter.drawText(QRect(100, 100, 200, 200), Qt::TextWordWrap, "line\nline2", &r);
我需要获得10个矩形,考虑换行,自动换行,标签等。
例如,由于换行符,第二个'l'
的矩形将位于第一个'l'
的矩形下方,而不是'e'
的右侧。
像这张照片中红色矩形的坐标(我把它们放在手边,所以它们不是真正正确的位置):
答案 0 :(得分:4)
这可能不是最好的解决方案,但它是我能想到的最好的解决方案。
我相信你必须“自己动手”。也就是说,不是绘制文本块,而是一次绘制一个字符。然后,您可以使用QFontMetrics获取每个字符的边界框。
这是一项小工作,但也不算太糟糕。像(伪代码,而不是代码):
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
}
查看QFontMetrics,它有许多不同的方法来获取边界框,最小边界框等。
啊......我现在看到你正在使用的重载会返回实际的边界矩形。如果您愿意,您可以使用它并跳过QFontMetrics - 否则整体算法是相同的。
答案 1 :(得分:3)
您可以使用QFontMetrics::boundingRect(QChar)
检索单个字符的边界框,但必须从顶部的QFontMetrics::ascent
以及前面字符的QFontMetrics::width
进行渲染。左边)因为它们是相对于字体的基线而不是相对于整个字符串的边界框的底部。
还必须单独处理几行。
QFontMetrics::lineSpacing
给你抵消。
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()});
}
}
结果
遗憾的是,这并不完美。