Для Qt 4.6.x, как авто-размер текста, чтобы вписаться в заданную ширину?

внутри моего 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));
 }
}

7 ответов


Йоханнес из qtcentre.org предложено следующее решение:

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);
 }

Я дал ему попробовать в своей программе, и до сих пор, похоже, работает довольно хорошо. Мне это нравится, потому что он дает результаты за один проход, но он предполагает, что ширина шрифта масштабируется как его высота.

http://www.qtcentre.org/threads/27839-For-Qt-4-6-x-how-to-auto-size-text-to-fit-in-a-specified-width


У вас может быть qgraphicstextitem как дочерний элемент элемента rect, измерьте ширину текстового элемента, а затем масштабируйте текстовый элемент (setTransform ()), чтобы вписаться в ширину (и высоту) элемента rect.


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);

 }

или точнее, но жадный

 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);
     }
 }

поделить покорить:

вы можете уменьшить количество проходов в вашем методе грубой силы: допустим, ваш предпочтительный (максимальный) размер шрифта 40 и у вас минимальный размер шрифта 0

if (40 == false && 0 == true)

  • 20=true / / разделить возможности пополам с каждой догадкой
  • 30=false
  • 25=true
  • 27=true
  • 28=false
  • так 27 wins

в чем это лучше?

это заняло 6 догадок вместо 13, и даже если 20, 12 или 39 были правильным ответом, это всегда займет около 6 догадок. так что это не только меньше догадок большую часть времени, это более последовательно, что важно для пользовательского опыта.

Я думаю, что количество догадок, которое требуется при делении ints на половину каждый раз, является квадратным корнем диапазона, который вы смотрите в плюс один. Математика.sqroot(40-0) + 1 (это всего лишь догадка, не стесняйтесь поправлять меня.) ваш минимальный размер шрифта, вероятно, не равен 0, поэтому увеличение этого ускорит поиск ответа.

иллюстрации:

Это как играть угадайте, кто, игроки, которые спрашивают "есть ли у вашего имени" А "и сокращает возможности пополам независимо от того, что вы отвечаете, как правило, находит ответ быстрее, чем игрок, который спрашивает о 1 символе каждый ход" это ваше имя Сэм "" это ваше имя Алекс"

альтернатива: начиная с хорошей догадки, а затем тестирование на точность Я хотел бы также поощрять работу в какую-то логику в использовании результат обеспечивается Дарен ответ с помощью fontMetrics-хорошее начало думаю, а затем проверить, если он подходит Тест +2, если он не подходит Тест -2; если новый тест подходит для тестирования 1 вы пропустили, и вы будете знать ответ на свой вопрос, если не попробовать еще 2 и так далее, но в идеале fontMetrics ответа не более 4 за горами...

I подозреваю, что это даст самые быстрые средние результаты фактических случаев использования.

предполагая, что вы хотите int и предполагая, что неточности метрик шрифта минимальны, это, вероятно, займет всего 2 или 3 догадки.


вот мой код подходит (в heigth) текст, работает довольно хорошо (Ошибка

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);
}

к сожалению, нет. Здесь нет простого решения. Наиболее очевидным улучшением с точки зрения производительности было бы вычисление и кэширование необходимого размера шрифта при изменении текста вместо его пересчета в каждом paintEvent. Другим улучшением было бы попытаться оценить правильный размер в зависимости от пропорций прямоугольника. Создание и тестирование оценок должно заставить вас исправить размер намного быстрее, чем просто уменьшить размер точки на одну итерацию.


Это зависит от диапазона, в котором вы ожидаете, что ваши размеры шрифта будут отличаться. Если диапазон большой, увеличение на единицу может занять много времени. Если это всего лишь вопрос нескольких размеров точек, скорость, вероятно, не будет проблемой.

Если диапазон большой, другим подходом было бы добавить больший интервал вместо "1". Если вы превысите желаемый размер за один шаг, уменьшите интервал, скажем, наполовину. Вы будете подпрыгивать взад и вперед по оптимальному размеру все меньше и меньше суммы каждый раз; когда разница между двумя последовательными интервалами времени мало, можно бросить.

Это похоже на подход, используемый в поиск корней. Это может быть излишним, так как размер шрифтов, которые будут приемлемы для отображения в данном приложении, вероятно, будет довольно узким, и подход грубой силы, который вы уже используете, не займет много времени.