【问题标题】:QPainter::drawText, get bounding boxes for each characterQPainter::drawText,获取每个字符的边界框
【发布时间】:2012-11-02 02:06:26
【问题描述】:

我正在使用 QPainter 在 QImage 上绘制多行文本。但是,我还需要在每个字符的边界框周围显示一个彩色矩形。

所以我需要知道每个角色在绘制时的边界框。

例如,对于

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

考虑到换行符、自动换行、制表符等,我需要得到 10 个矩形。

例如,第二个'l' 的矩形将位于第一个'l' 的矩形下方,而不是在'e' 的右侧,因为换行符。

类似于这张图片中红色矩形的坐标(我是手动放置的,所以它们并不是真正正确的位置):

【问题讨论】:

    标签: c++ qt qpainter drawtext


    【解决方案1】:

    您可以使用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()});
        }
    }
    

    结果

    遗憾的是,这并不完美。

    【讨论】:

      【解决方案2】:

      这可能不是最好的解决方案,但它是我能想到的最好的解决方案。

      我相信您将不得不“自己动手”。也就是说,不是绘制一个文本块,而是一次绘制一个字符。然后就可以使用 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 4.7

      啊...我现在看到您正在使用的重载返回实际的边界矩形。如果您愿意,可以直接使用它并跳过 QFontMetrics - 否则整体算法是相同的。

      【讨论】:

      • 好的,谢谢,大家都试着去实现它。我正在考虑找到the actual source codethe actual source code 并使用它,但结果太复杂了,我什至找不到角色的实际绘制位置。绘图由一个非常大的函数qt_format_text 处理,我认为他们使用QTextLine 进行绘图。
      猜你喜欢
      • 2012-06-29
      • 2017-06-15
      • 2021-01-14
      • 2013-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      • 1970-01-01
      相关资源
      最近更新 更多