Установите текстовое содержимое QGraphicsTextItem точной высоты и ширины

Мне нужно создать текстовые элементы с точной шириной и высотой текстового содержимого.
Высота текста является наиболее важным требованием.
Положение текста должно быть относительно сам текст.

Я также должен быть в состоянии разместить его на холсте в точном месте.

Предполагая (пригодный для печати) холст (на большем QGraphicsScene), скажем, 5 дюймов в ширину и 1 дюйм в высоту, мой текст должен иметь возможность растягиваться сверху-снизу-влево-вправо - и быть помещенным на холст, а не часть в часть.


Я создаю подкласс QGraphicsTextItem для своего типа элемента. Я изменяю его размер, используя QTransform(), до требуемого размера - в дюймах, мм или пикселях (72*дюйма).
Также устанавливаю поле document() равным 0, а все внутри (например, поля QTextBlockFormat) также равным 0.

Я реализовал setItemSize(QSizeF sz) (с sz в пикселях), который изменяет размер QGraphicsTextItem по мере необходимости.
sz инициализируется с использованием прямоугольника, ограничивающего элемент.
Предполагая отсутствие переноса, однострочный текст (многострочный может быть решен отдельно как только этот вопрос будет решен).

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


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

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

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


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

введите здесь описание изображения

Выше были эксперименты с функцией рисования текстового элемента, наследующего QGraphicsTextItem:

void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    // draw text
    QGraphicsTextItem::paint(painter, option, widget);

    QPen p;
    p.setWidthF(0);
    QFontMetricsF fm(this->font());
    qreal ascent = fm.ascent(),
          descent = fm.descent(),
          hheight = fm.height();
    QRectF r = QGraphicsTextItem::boundingRect();
    QRectF rFont= fm.tightBoundingRect(toPlainText());

    qreal xmax = r.right();

    painter->save();
    painter->setBrush(Qt::NoBrush);

    // where is "ascent + descent"
    p.setColor(Qt::green);
    painter->setPen(p);
    painter->drawLine(QPointF(2, ascent), QPointF(2, ascent + descent));
    painter->drawLine(QPointF(2, ascent + descent), QPointF(xmax/2, ascent + descent));

    // where is "height"
    p.setColor(Qt::red);
    painter->setPen(p);
    painter->drawLine(QPointF(xmax/2, 0), QPointF(xmax/2, hheight));
    painter->drawLine(QPointF(xmax/2, ascent + descent), QPointF(xmax, ascent + descent));

    // where is "ascent"
    p.setColor(Qt::yellow);
    painter->setPen(p);
    painter->drawLine(QPointF(6, 0), QPointF(6, ascent));
    painter->drawLine(QPointF(6, ascent), QPointF(xmax, ascent));

    // something that may look like top of the text
    p.setColor(Qt::blue);
    painter->setPen(p);
    qreal yyy = ascent + rFont.y() + 1;
    painter->drawLine(QPointF(5, yyy), QPointF(xmax, yyy));

    // this should be useful... should be the natural offset
    qreal yoffset = (r.height() - rFont.height()) / 2;
//    qDebug() << yoffset << r << rFont;
    //qreal y0 = (r.height() - fm.height())/2;

    p.setColor(Qt::darkGreen);
    painter->drawEllipse(10, yoffset, 1, 1);

    // where is the font rect
    p.setColor(Qt::magenta);
    painter->setPen(p);
    yoffset = (r.height() + rFont.height()) / 2;
    painter->translate(0, yoffset);
    painter->drawRect(rFont);
    painter->restore();
}

Я также пробовал не использовать QGraphicsTextItem, а рисовать текст внутри прямоугольника. То же самое происходит.

(Qt 4.7 - 5.x)


person Thalia    schedule 09.06.2016    source источник
comment
Пожалуйста, предоставьте скриншот того, что вы видите и что вы ожидаете. У меня такое ощущение, что вы боретесь с восхождением или чем-то подобным.   -  person Marek R    schedule 14.06.2016
comment
@MarekR - я добавил свою функцию для расчета позиции и снимков экрана в своем ответе ниже.   -  person Thalia    schedule 14.06.2016


Ответы (1)


Это не очень хорошее решение. Это попытка решить мою собственную проблему — в первой итерации — установки текста с заданной шириной и высотой с использованием метрик шрифта.

Причины не быть хорошим -

  • Даже после изменения размера текст меньше, чем хотелось бы, я не понимаю, почему

  • Позиция неверна, в зависимости от стиля шрифта текст может быть выше или ниже холста, что означает, что он обрезается.


Я изменяю его размер, используя коэффициент, рассчитанный на основе размера ограничивающего прямоугольника элемента и ограничивающего прямоугольника метрик шрифта (я использовал плотный ограничивающий прямоугольник для более точного размера).

myText->setItemFontSize(12);   // If I use font metrics I need to reset text size on every change, because resizing loses font info 
QFontMetricsF fm(myText->font());
QRectF fmRect = fm.tightBoundingRect(myText.toPlainText().toUpper());
// without toUpper() the size is too small - even so it is a bit small
// I read tightBoundingRect is slow - but boundingRect and height and ascent all give values that result in even smaller size
//qreal absH = fm.ascent();
qreal absH = fmRect.height();
qreal absW = fmRect.width();
qreal absHeightRatio = myText->getItemSize().height() / absH;
qreal absWidthRatio = myText->getItemSize().width() / absW;

Затем установка размера:

myText->setItemSize(QSizeF(absWidthRatio * textLength, absHeightRatio * fontHeight));
// This function scales the `QTransform` on item
// but since I request a final position dependent on item size 
// (including blank space around it) - it has no chance of being accurate..... 
// This is where my next effort will go, figuring out how to get rid of the fluff 
// around the item inside the scaling

Функция установки позиции: попытка центрировать текст:

// leftShift  = 10, rightShift = 10 in example
myText->setPos(0,0);
QRectF r = myText->mapToScene(myText->boundingRect()).boundingRect();
QSizeF sz = r.size();
qreal w = sz.width();
qreal h = sz.height();
qreal cx = (m_docLength - w + leftShift - rightShift)/2 - r.left();
qreal cy = (m_docHeight - h)/2 - r.top();
myText->setPos(cx, cy);

Изображения ниже предназначены для fontHeight = m_docHeight -

Желательно:
- либо весь размер текста (по восходящей + нисходящей) равен высоте документа, а текст центрирован по вертикали на основе содержимого
- либо размер текста в верхнем регистре равен высоте документа, а спуск находится под документом (текст по центру на основе только верхнего регистра) - это может показаться проще, исходя из того, как QGraphicsTextItem кажется позиционирует его

Факт:
 – текст мельче независимо от того, какие параметры я использую для масштабирования, и выравнивается по центру на основе текста в верхнем регистре.

введите здесь описание изображения

Как показано выше - я понятия не имею, как я могу центрировать по вертикали на основе содержимого (так что для текста от края до края подходит спуск) - и вместо этого все, что я действительно хочу, это заглавные буквы от края до края , но я не могу этого добиться.

О, и это для шрифта типа Arial - один из лучших. Другие шрифты прыгают повсюду, выше или ниже холста. И для некоторых шрифтов результирующий текст на самом деле меньше, что для меня необъяснимо, потому что как может узкий ограничивающий прямоугольник быть меньше, чем ограничивающий прямоугольник элемента...

Тем не менее, это все, что мне удалось сделать, чтобы мой текст был максимально близок к «истинному» размеру и размещен на холсте, который соответствует его размеру.

person Thalia    schedule 10.06.2016
comment
Попробуйте использовать QFontMetricsF вместо QFontMetrics. У меня было несколько кошмаров от этого раньше. - person p4plus2; 14.06.2016
comment
@ p4plus2 - я заменил его, но не вижу изменений. - person Thalia; 14.06.2016