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

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

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

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


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

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

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


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

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

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


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

Выше были эксперименты в функции рисования текстового элемента наследования 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)

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 типа - один из лучших. Другие шрифты прыгают повсюду, либо над, либо под холстом. А для некоторых шрифтов результирующий текст на самом деле меньше, что для меня необъяснимо, потому что как ограничивающий прямоугольник может быть меньше, чем ограничивающий прямоугольник элемента...

Тем не менее, это все, что мне нужно, чтобы мой текст был максимально приближен к "истинному" размеру и помещен на холст, соответствующий его размеру.

Другие вопросы по тегам