Qt获取一个适合于固定QRect内的大QString的子字符串

3

我有一段很长的字符串,一个固定的字体和一个固定的矩形来绘制这个字符串。

  • 如果字符串不适合矩形,我想知道适合在该矩形内的子字符串长度
  • 如果字符串适合矩形,那么我想知道边界矩形的高度

我整天在网上搜索,但没找到任何资料。


1
QFontMetrics :: boundingRect和启发式搜索? - peppe
1
我可以创建一个类似于二分查找的算法,使用boundingRect()函数来查找符合条件的子字符串,但我认为这可能非常低效。 - Borzh
2个回答

1
使用QFontMetrics类及其boundingRect类,获取提供的字符串所用的矩形。
// assumes myFont has been instantiated
QFontMetrics fm(myFont);
QRect bounds = fm.boundingRect("Some text here");

将边界大小与测试字符串适合的区域进行比较。

如果字符串不适合,我想知道适合该矩形的子字符串的长度

如果从boundingRect返回的矩形的边界太大,则递归地删除字符,直到宽度适合目标矩形为止。

bool bFits = false;
QString str = "String to test boundary";
QFontMetrics fm(myFont);
QRect bounds;
do
{    
    bounds = fm.boundingRect(str);
    // Assume testBoundary is the defined QRect of the area to hold the text
    if(!testBoundary.contains(bounds) && (!str.isEmpty()) )
         str.chop(1);
    else
        bFits = true;
}while(!bFits);

如果字符串适合,那么我想知道边界矩形的高度。
这只是从调用boundingRect返回的矩形的高度。
int height = bounds.height();

我也想到了这个问题,但是我认为删除字符/单词/行会非常低效,因为算法总是在计算相同字符串的边界矩形。有没有其他方法可以计算这个? - Borzh
2
除非字符串非常长,否则性能可以忽略不计。在注意到这样的问题之前,您不应该过于担心性能,此时您可以对应用程序进行分析并在必要时进行优化。当然,牢记良好的编程习惯并不是坏事,但在这里不应该成为问题。 - TheDarkKnight
2
将这些计算结果绘制到与矩形大小相同的像素图上可能是个不错的主意。在以后的绘图事件中,您只需要使用QPainter::drawPixmap绘制该像素图。仅当字符串或矩形大小发生更改时才重新绘制该像素图。这可以大大加快绘图速度..也就是说,将计算从paintEvent中移出。 - Aaron
当然,我只是想看看是否有人想发表另一个答案。 - Borzh
2
一个简单的优化方法是使用“二分查找”来查找最大长度,而不是使用chop(1)。 - Frank Osterfeld
显示剩余3条评论

1
我正在发布自己的二分查找算法。Batman 指出了正确的方向,谢谢!顺便说一句,如果你想的话,可以使用 QFontMetrics 而不是 QPainter
int FontUtils::FittingLength(const QString& s, QPainter &p, const QRectF& rect,
                             int flags/* = Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap*/)
{
    QRectF r = p.boundingRect(rect, flags, s);
    if (r.height() <= rect.height()) // String fits rect.
        return s.length();

    // Apply binary search.
    QString sub;
    int left = 0, right = s.length()-1;
    do
    {
        int pivot = (left + right)>>1; // Middle point.
        sub = s.mid(0, pivot+1);
        r = p.boundingRect(rect, flags, sub);

        if (r.height() > rect.height()) // Doesn't fit.
            right = pivot-1;
        else
            left = pivot+1;
    } while (left < right);

    left++; // Length of string is one char more.

    // Remove trailing word if it doesn't fit.
    if  ( !s.at(left).isSpace() && !s.at(left+1).isSpace() )
    {
        while ( (--left > 0) && !sub.at(left).isSpace() );
        left++;
    }

    return left;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接