Для Qt 4.6.x, как автоматически изменить размер текста, чтобы он соответствовал заданной ширине? - PullRequest
17 голосов
/ 04 февраля 2010

Внутри моего 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 ]

14 голосов
/ 05 февраля 2010

Йоханнес из 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

2 голосов
/ 25 июля 2016

Вот мой код, который подходит (по высоте) тексту, работает довольно хорошо (ошибка <2%, я думаю) </p>

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);
}
2 голосов
/ 03 марта 2010

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

1 голос
/ 23 сентября 2015

Разделить победителя:

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

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

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

Каким образом это лучше?

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

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

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

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

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

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

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

1 голос
/ 15 июля 2011
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);
     }
 }
0 голосов
/ 12 апреля 2010

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

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

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

0 голосов
/ 05 февраля 2010

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

...