对于Qt4.6.x,如何自动调整文本大小以适应指定的宽度?

对于Qt4.6.x,如何自动调整文本大小以适应指定的宽度?,qt,font-size,autosize,Qt,Font Size,Autosize,在我的QGraphicsRectItem::paint()中,我试图在其rect()中绘制项的名称。但是,对于每个不同的项目,它们可以具有可变的宽度,同样,名称也可以具有可变的长度 目前,我从一个最大字体大小开始,检查它是否适合,并逐渐减小,直到找到适合的字体大小。到目前为止,我还没有找到一个快速简单的方法来完成这项工作。有没有更好或更有效的方法 谢谢 void checkFontSize(QPainter *painter, const QString& name) { // che

在我的QGraphicsRectItem::paint()中,我试图在其rect()中绘制项的名称。但是,对于每个不同的项目,它们可以具有可变的宽度,同样,名称也可以具有可变的长度

目前,我从一个最大字体大小开始,检查它是否适合,并逐渐减小,直到找到适合的字体大小。到目前为止,我还没有找到一个快速简单的方法来完成这项工作。有没有更好或更有效的方法

谢谢

void checkFontSize(QPainter *painter, const QString& name) {
 // check the font size - need a better algorithm... this could take awhile
 while (painter->fontMetrics().width(name) > rect().width()) {
  int newsize = painter->font().pointSize() - 1;
  painter->setFont(QFont(painter->font().family(), newsize));
 }
}

不幸的是,没有。没有简单的解决办法。性能方面最明显的改进是在文本更改时计算并缓存所需的字体大小,而不是在每个事件中重新计算。另一个改进是尝试根据边界矩形的比例估计正确的大小。做出和测试评估应该可以让您更快地纠正大小,而不是简单地每次迭代减少一个点大小。

来自qtcentre.org的Johannes提供了以下解决方案:

float factor = rect().width() / painter->fontMetrics().width(name);
 if ((factor < 1) || (factor > 1.25))
 {
  QFont f = painter->font();
  f.setPointSizeF(f.pointSizeF()*factor);
  painter->setFont(f);
 }
float factor=rect().width()/painter->fontMetrics().width(名称);
如果((系数<1)| |(系数>1.25))
{
QFont f=画师->字体();
f、 setPointSizeF(f.pointSizeF()*因子);
画师->设置字体(f);
}
我在我的程序中尝试了一下,到目前为止,它似乎运行得很好。我喜欢它,因为它只需一次就可以产生结果,但它假设字体宽度的比例与其高度相同


您可以将QGraphicsTextItem作为rect项的子项,测量文本项的宽度,然后缩放文本项(setTransform())以适应rect项的宽度(和高度)。

这取决于您希望字体大小变化的范围。如果范围较大,则按1递增可能需要很长时间。如果只是几个点大小的问题,速度可能不会成为问题

如果范围较大,另一种方法是增加较大的间隔,而不是“1”。如果您在一个步骤中超过了所需的大小,请将间隔减少一半。你会在最佳尺寸上来回弹跳,每次弹跳的幅度越来越小;当两个连续间隔之间的差值很小时,您可以退出

这类似于根查找中使用的方法。这可能有点过分,因为在给定的应用程序中可以接受的字体大小可能相当窄,并且您已经使用的暴力方法不会占用太多时间。

void myClass::AdapterFontSize(qPaint*painter、int标志、QRectF drawRect、QString文本){
void myClass::adaptFontSize(QPainter * painter, int flags, QRectF drawRect, QString text){
     int flags = Qt::TextDontClip|Qt::TextWordWrap; //more flags if needed
     QRect fontBoundRect = 
           painter->fontMetrics().boundingRect(drawRect.toRect(),flags, text);
     float xFactor = drawRect.width() / fontBoundRect.width();
     float yFactor = drawRect.height() / fontBoundRect.height();
     float factor = xFactor < yFactor ? xFactor : yFactor;
     QFont f = painter->font();
     f.setPointSizeF(f.pointSizeF()*factor);
     painter->setFont(f);

 }
int flags=Qt::TextDontClip | Qt::TextWordWrap;//如果需要,请提供更多标志 QRect fontbundrect= 画师->fontMetrics().boundingRect(drawRect.toRect(),标志,文本); float xFactor=drawRect.width()/fontbundrect.width(); float yFactor=drawRect.height()/fontBoundRect.height(); 浮动系数=xFactor字体(); f、 setPointSizeF(f.pointSizeF()*因子); 画师->设置字体(f); }
或者更准确但贪婪

 void myClass::adaptFontSize(QPainter * painter, int flags, QRectF rect, QString text, QFont font){
     QRect fontBoundRect;
     fontBoundRect = painter->fontMetrics().boundingRect(rect.toRect(),flags, text);
     while(rect.width() < fontBoundRect.width() ||  rect.height() < fontBoundRect.height()){
         font.setPointSizeF(font.pointSizeF()*0.95);
         painter->setFont(font);
         fontBoundRect = painter->fontMetrics().boundingRect(rect.toRect(),flags, text);
     }
 }
void myClass::AdapterFontSize(QPaint*painter、int标志、QRectF rect、QString文本、QFont字体){
QRect-fontbundrect;
fontBoundRect=画师->fontMetrics().boundingRect(rect.toRect(),标志,文本);
而(rect.width()设置字体(字体);
fontBoundRect=画师->fontMetrics().boundingRect(rect.toRect(),标志,文本);
}
}

分而治之:

您可以减少蛮力方法中的传递次数: 假设您的首选(最大)字体大小为40,最小字体大小为0

如果(40==false&&0==true)

  • 20=真//用每个猜测将可能性一分为二
  • 30=错误
  • 25=正确
  • 27=正确
  • 28=错误
  • 所以27胜
这在哪些方面更好?

这需要6次猜测而不是13次,即使20次、12次或39次是正确答案,也总是需要6次猜测。因此,它不仅在大多数情况下减少了猜测,而且更加一致,这对用户体验非常重要

我认为每次将整数除以一半所需的猜测数是所查找范围的平方根加1。sqroot(40-0)+1(这只是一个猜测,请随意更正。) 您的最小字体大小可能不是0,因此增加此值将加快搜索答案的速度

插图:

这就像玩猜猜谁的游戏,玩家问“你的名字有A吗”并将可能性减半,不管你回答什么,通常比每回合问1个字符的玩家更快找到答案“是你的名字Sam”“是你的名字Alex”

备选方案:从一个好的猜测开始,然后测试准确性 我也会促进在一些逻辑中使用Daren的答案提供的结果,使用fontMetrics作为一个好的开始猜测,然后测试它,如果它符合test+2,如果它不符合test-2;如果新测试符合您跳过的测试1,您将知道您的答案,如果不符合,请尝试移动另一个测试2,以此类推,但理想情况下,fontMetrics答案不会超过4

我怀疑这将产生实际用例的最快平均结果

假设您需要一个int,并且假设字体度量的不准确度最小,这可能只需要2到3次猜测。

这是我的代码,适合(高度)文本,效果非常好(我猜错误<2%)

void scalePainterFontSizeToFit(QPainter&painter,QFont&r_字体,float_字体高度)
{
浮动oldFontSize、newFontSize、oldHeight;
//初始化
oldFontSize=r_font.pointSizeF();
//环路
对于(int i=0;i跟随函数
void scalePainterFontSizeToFit(QPainter &painter, QFont &r_font, float _heightToFitIn)
{
    float oldFontSize, newFontSize, oldHeight;

    // Init
    oldFontSize=r_font.pointSizeF();

    // Loop
    for (int i=0 ; i<3 ; i++)
    {
        oldHeight = painter.fontMetrics().boundingRect('D').height();
        newFontSize = (_heightToFitIn / oldHeight) * oldFontSize;
        r_font.setPointSizeF(newFontSize);
        painter.setFont(r_font);
        oldFontSize = newFontSize;
        //qDebug() << "OldFontSize=" << oldFontSize << "HtoFitIn=" << _heightToFitIn << "  fontHeight=" << oldHeight << "  newFontSize=" << newFontSize;
    }

    // End
    r_font.setPointSizeF(newFontSize);
    painter.setFont(r_font);
}
QFont optimizeFontSizeToFitTextInRect(QPainter * painter, QRectF drawRect, QString text, int flags = Qt::TextDontClip|Qt::TextWordWrap, double goalError =  0.01, int maxIterationNumber=10){
    painter->save();

    QRect fontBoundRect;
    QFont font;
    double minError = std::numeric_limits<double>::max();
    double error = std::numeric_limits<double>::max();
    int iterationNumber=0;
    while((error > goalError) && (iterationNumber<maxIterationNumber)){
        iterationNumber++;
        fontBoundRect = painter->fontMetrics().boundingRect(drawRect.toRect(),flags, text);
        double xFactor = drawRect.width() / fontBoundRect.width();
        double yFactor = drawRect.height() / fontBoundRect.height();
        double factor;
        if (xFactor<1 && yFactor<1) {
            factor = std::min(xFactor,yFactor);
        } else if (xFactor>1 && yFactor>1) {
            factor = std::max(xFactor,yFactor);
        } else if (xFactor<1 && yFactor>1) {
            factor = xFactor;
        } else {
            factor = yFactor;
        }
        error = abs(factor-1);
        if (factor > 1 ) {
            if (error < minError) {
                minError = error;
            } else {
                break;
            }
        }
        font = painter->font();
        font.setPointSizeF(font.pointSizeF()*factor);
        painter->setFont(font);
    }
    painter->restore();

    return font;
}