设置QGraphicsTextItem文本内容的精确高度和宽度

时间:2016-06-09 21:22:46

标签: qt qtextdocument qgraphicstextitem

我需要创建文本内容的确切宽度和高度的文本项 文本的高度是最重要的要求 文本的位置应该与文本本身有关。

我还必须能够将它放在画布上的确切位置。

假设一个(可打印的)画布(在较大的QGraphicsScene上),比如5英寸宽和1英寸高,我的文字应该能够伸展到上下左下 - 并放在画布上,不参与其中。

我正在为我的项目类型对QGraphicsTextItem进行子类化。我正在使用QTransform()将其调整为所需大小 - 以英寸或毫米或像素(72 *英寸)为单位。
同时将document()边距设置为0,内部任何内容(如QTextBlockFormat边距)也设置为0.

我已经实现了setItemSize(QSizeF sz)(以像素为单位的sz),可根据需要调整QGraphicsTextItem的大小。
使用项目边界rect初始化sz 假设没有换行,单行文本(解决此问题后可以单独解决多行)。

将项目添加到画布时,我仍然会看到顶部和底部边距 - 这会因字体选择而异 我在项目周围画了一个矩形来看它 顶部/底部距离取决于字体选择。

我尝试使用字体指标来确定这些距离(在paint()中我一直在绘制线条以尝试确定文本适合的位置和矩形。)

我很乐意至少能够确定用于大写字母,没有重音符号或特殊字符字体的正确大小(这将是一个开始,但自然我需要能够使用任何字符)。<登记/> 但至少有一些方法可以确定文本内容的大小和位置(相对于项目的(0,0)),即使在最简单的情况下......

字体指标tightBoundingRect()似乎是最准确的大小,但似乎无法确定其位置,以便我可以以某种方式正确创建我的项目,并可能正确调整大小/移位它们以适合画布。

以下是我努力确定至少相对于项目的(0,0)的文本的确切大小和位置的一些示例(假设一旦我这样做,我能够将该信息暴露给外部或在调整大小时包括项目转换中的转换 请注意,字体度量标注的文本大小并不总是覆盖文本,对于不同的字体,我无法在文本本身周围放置紧束缚矩形(洋红色)。 (我做了多次猜测,下面的代码只有一个 - 这些行试图显示不同的字体指标大小)。

enter image description here

以上是继承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 个答案:

答案 0 :(得分:2)

这不是一个好的解决方案。这是尝试使用字体指标解决我自己的问题 - 在第一次迭代中 - 使用给定的宽度和高度设置文本。

不好的原因 -

  • 即使调整大小后,文字也比预期的要小,我也不明白为什么

  • 位置不正确,根据字体样式,文字可以在画布的上方或下方,这意味着它会被裁剪。

我使用从项目边界大小计算的因子和限制矩形的字体度量来调整大小(我使用紧定边界矩形来获得更准确的大小)。

git stash

然后设置尺寸:

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

以下图片适用于fontHeight = m_docHeight -

理想的:
- 文本的整个大小(上升+下降)等于文档高度,文本根据内容垂直居中 - 或大写字母大小的文本等于doc高度,下降位于文档下方(文本仅基于大写字母居中) - 根据// 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); 的定位方式,这似乎更容易

实际:
- 无论我使用哪种参数进行缩放,文本都更小,并以大写文本为中心

enter image description here

如上所示 - 我不知道如何根据内容垂直居中(因此对于下降到适合的边缘到边缘文本) - 而且取而代之的是,我真正想要的只是边缘到 - 边缘大写字母,但我似乎无法实现这一点。

哦,这些是Arial字体 - 最好的表现之一。其他字体遍布画布的上方或下方。对于某些字体,生成的文本实际上更小 - 这对我来说是无法解释的,因为紧密边界矩形如何小于项目边界矩形......

仍然这是我的文字尽可能接近&#34; true&#34;大小并放在与其大小相匹配的画布上。