6

テキスト コンテンツの正確な幅と高さでテキスト アイテムを作成する必要があります。
テキストの高さは最も重要な要件です。
テキストの位置は、テキスト自体に対して相対的でなければなりません。

また、キャンバス上の正確な場所に配置できる必要があります。

(印刷可能な)キャンバス(より大きなQGraphicsScene)、たとえば幅5インチ、高さ1インチと仮定すると、テキストは上下左右に引き伸ばされ、部分的にではなくキャンバスに配置されるはずです。


QGraphicsTextItemアイテム タイプのサブクラス化を行っています。を使用してQTransform()、必要なサイズ (インチ、mm、またはピクセル (72 * インチ)) にサイズ変更しています。
また、document()マージンを 0 に設定し、内部 (QTextBlockFormatマージンなど) もすべて 0 に設定します。

setItemSize(QSizeF sz)必要に応じてサイズを変更する(ピクセル単位のsz)を実装しましたQGraphicsTextItem
sz はアイテムのバウンディング rect を使用して初期化されます。
折り返されていないと仮定すると、1 行のテキスト (この問題が解決されれば、複数行のテキストは個別に解決される可能性があります)。

項目をキャンバスに追加すると、まだ上下の余白が表示されますが、これはフォントの選択によって異なります。
アイテムを表示するために、アイテムの周りに四角形を描きました。
上/下の距離は、フォントの選択によって異なります。


これらの距離を決定するためにフォント メトリックを使用しようとしましpaint()た (テキストが収まる位置と四角形を決定するために線を引いています)。

少なくとも、大文字、アクセントまたは特殊文字のフォントに使用する正しいサイズを決定できれば幸いです(もちろん、任意の文字を使用できる必要がありますが、それは出発点です)。しかし、最も単純なケースであっても、テキストコンテンツのサイズと位置(アイテムの (0,0) に相対的)
を決定する少なくとも何らかの方法.....

フォント メトリックtightBoundingRect()はサイズに関して最も正確に見えますが、その位置を特定することは不可能であるため、どうにかしてアイテムを正しく作成し、キャンバスに収まるように正しくサイズ変更/シフトすることができます。


アイテムの (0,0) に対するテキストの少なくとも正確なサイズと位置を決定するのに苦労した例をいくつか示します (これを行うと、その情報を外部に公開するか、シフトを含めることができると仮定します)。サイズ変更時にアイテムが変換されます)。
フォント メトリックによってアドバタイズされるテキストのサイズが常にテキストをカバーするとは限らないことに注意してください。また、フォントが異なると、テキスト自体の周りにタイトな境界四角形 (マゼンタ) を配置することができません。(複数の推測を行いました。以下のコードは 1 つにすぎません。行はさまざまなフォント メトリック サイズを表示しようとしています)。

ここに画像の説明を入力

上記は、テキストアイテム継承のペイント機能の実験でした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)

4

1 に答える 1

3

これは良い解決策ではありません。これは、フォント メトリックを使用して、指定された幅と高さでテキストを設定するという、最初の繰り返しでの私自身の問題を解決する試みです。

良くない理由 -

  • サイズを変更してもテキストが小さいのですが、理由がわかりません

  • 位置が正しくありません。フォント スタイルに基づいて、テキストがキャンバスの上または下になる可能性があります。つまり、テキストが切り取られます。


アイテムのバウンディング rect サイズとフォント メトリックのバウンディング rect から計算された係数を使用してサイズを変更します (より正確なサイズを得るために、タイトなバウンディング rect を使用しました)。

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 タイプのフォント用です。他のフォントは、キャンバスの上または下のいたるところにジャンプします。また、一部のフォントでは、結果のテキストが実際には小さくなります-これは私には説明できません。なぜなら、タイトな境界四角形がアイテムの境界四角形よりも小さくなる可能性があるからです...

それでも、これはテキストを「真の」サイズに近づけて、そのサイズに一致するキャンバスに配置できる限りです。

于 2016-06-10T16:53:36.710 に答える