8

QGraphicsItem を親とする QGraphicsTextItem があります。QGraphicsTextItem を常に QGraphicsItem の真上に配置したいのですが、縮尺係数が 1 を下回ったときにテキストを同じサイズのままにしたい、つまり、親グラフィックがアイテムは縮小されています。QGraphicsItem::ItemIgnoresTransformationsスケール係数が 1 未満の場合にフラグを true に設定すると、サイズを保持するためのトリックが実行されることがわかりました。

しかし、テキストの位置を常に QGraphicsItem の上に保つ方法を見つけることができないようです。これを行う方法はありますか?関数を使用してみdeviceTransform ()ましたが、スクロールアウトするとテキストが QGraphicsItem から移動しました。さらに悪いことに、一部のテキスト項目が「揺れ」始めました。つまり、位置が非常にわずかに変化し続けたため、揺れているように見えました。これが私が使用する必要がある機能である場合、私はそれを適切に使用する方法を知らないと思います.

QGraphicsItem のコンストラクターで、QGraphicsTextItem を追加しました。

fTextItem = new QGraphicsTextItem(getName(), this);
fTextItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);

QGraphicsItem のペイント関数のコード スニペットを次に示します。

qreal lod = painter->worldTransform().m22();
if(lod <= 1.0) {
     fTextItem-setFlag(QGraphicsItem::ItemIgnoresTransformations);
     fTextItem->setPos(fTextItem->deviceTransform(view-viewportTransform()).inverted().map(view->mapFromScene(mapToScene(0,0))));
} else {
     fTextItem->setFlag(QGraphicsItem::ItemIgnoresTransformations, false);
     fTextItem->setPos(0, 0);
}
4

6 に答える 6

6

私の提案は、この方法で QGraphicsSimpleTextItem をサブクラス化することです:

class TextItem
    : public QGraphicsSimpleTextItem
{
public:
    TextItem(const QString &text)
        : QGraphicsSimpleTextItem(text)
    {

    }
    void paint(QPainter *painter, 
        const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        painter->translate(boundingRect().topLeft());
        QGraphicsSimpleTextItem::paint(painter, option, widget);
        painter->translate(-boundingRect().topLeft());
    }
    QRectF boundingRect() const
    {
        QRectF b = QGraphicsSimpleTextItem::boundingRect();
        return QRectF(b.x()-b.width()/2.0, b.y()-b.height()/2.0, 
            b.width(), b.height());
    }
};
QGraphicsSimpleTextItem *mText = new TextItem("Item");
scene()->addItem(mText);
mText->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
mText->setPos(itemToFollow->pos());
于 2012-09-20T00:29:29.367 に答える
4

免責事項:これはあなたがやろうとしていることに対してやり過ぎかもしれません。私たちのプロジェクトにはいくつかの追加の制限があり、このソリューションが私たちにとって最も簡単でした.

プロジェクトで似たようなことをしなければなりませんでしたが、最終的には使用せずItemIgnoresTransformationsに独自の変換をロールするのが最も簡単でした。特定の位置にアイテムを描画するための平行移動のみ (スケーリングなし) の変換を作成するために使用する主な関数を次に示します。用途に合わせて変更できる場合があります。

static QTransform GenerateTranslationOnlyTransform(
    const QTransform &original_transform,
    const QPointF &target_point) {
  // To draw the unscaled icons, we desire a transform with scaling factors
  // of 1 and shearing factors of 0 and the appropriate translation such that
  // our icon center ends up at the same point. According to the
  // documentation, QTransform transforms a point in the plane to another
  // point using the following formulas:
  // x' = m11*x + m21*y + dx
  // y' = m22*y + m12*x + dy
  //
  // For our new transform, m11 and m22 (scaling) are 1, and m21 and m12
  // (shearing) are 0. Since we want x' and y' to be the same, we have the
  // following equations:
  // m11*x + m21*y + dx = x + dx[new]
  // m22*y + m12*x + dy = y + dy[new]
  //
  // Thus,
  // dx[new] = m11*x - x + m21*y + dx
  // dy[new] = m22*y - y + m12*x + dy
  qreal dx = original_transform.m11() * target_point.x()
             - target_point.x()
             + original_transform.m21() * target_point.y()
             + original_transform.m31();
  qreal dy = original_transform.m22() * target_point.y()
             - target_point.y()
             + original_transform.m12() * target_point.x()
             + original_transform.m32();

  return QTransform::fromTranslate(dx, dy);
}

使用するにはQPainter、paint メソッドに渡された変換を取得して、次のようにします。

painter->save();
painter->setTransform(GenerateTranslationOnlyTransform(painter->transform(),
                                                       some_point));
// Draw your item.
painter->restore();
于 2012-07-12T20:11:37.653 に答える
1

Dave Materによるすばらしい回答です。異なるズーム レベルで異なる倍率を定義したいという問題がありました。これが私がやった方法です:

void MyGraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    //save painter for later operations
    painter->save();
    QTransform originalTransform = painter->transform();
    QPointF originalCenter = rect().center();
    qreal dx = originalTransform.m11() * originalCenter.x() + originalTransform.m21() * originalCenter.y() + originalTransform.m31();
    qreal dy = originalTransform.m22() * originalCenter.y() + originalTransform.m12() * originalCenter.x() + originalTransform.m32();
    //normally our target scale factor is 1, meaning the item has keeps its size, regardless of zoom
    //we adjust the scale factor though when the item is smaller than one pixel in comparison to the background image
    qreal factor = 1.0;
    //check if scale factor if bigger that the item size, and thus it occupies less that a pixel in comparision to the background image
    if (rect().width() < originalTransform.m11()) {
        //calculate adjusted scale factor
        factor = originalTransform.m11() / rect().width();
    }
    //adjust position according to scale factor
    dx -= factor * originalCenter.x();
    dy -= factor * originalCenter.y();
    //set the new transform for painting
    painter->setTransform(QTransform::fromScale(factor, factor) * QTransform::fromTranslate(dx, dy));
    //now paint...
    QGraphicsXYZItem::paint(painter, option, widget);
    //restore original painter
    painter->restore();
}

その場合、外接する長方形も調整する必要があります。

QRectF MyGraphicsItem::boundingRect() const
{
    QRectF rect = QGraphicsEllipseItem::boundingRect();
    //this is a bit hackish, let me know if you know another way...
    if (scene() != NULL && scene()->views().at(0) != NULL)
    {
        //get viewport transform
        QTransform itemTransform = scene()->views().at(0)->transform();
        QPointF originalCenter = rect.center();
        //calculate back-projected original size of item
        qreal realSizeX = rect.width() / itemTransform.m11();
        qreal realSizeY = rect.height() / itemTransform.m11();
        //check if scale factor is bigger that the item size, and thus it occupies less that a pixel in comparison 
        //to the background image and adjust size back to equivalent of 1 pixel
        realSizeX = realSizeX < 1.0 ? 1.0 : realSizeX;
        realSizeY = realSizeY < 1.0 ? 1.0 : realSizeY;
        //set adjusted position and size according to scale factor
        rect = QRectF(rect.center().x() - realSizeX / 2.0, rect.center().y() - realSizeY / 2.0, realSizeX, realSizeY);
    }
    return rect;
}

このソリューションを使用すると、私の場合、アイテムは非常にうまく機能します。

于 2014-05-20T09:14:33.363 に答える
0

これは、非常に適度な複雑さで考案したソリューションです。

1) 親の boundingRect() を取得し、それをシーンにマップします 2) このポイント リストの最小の X と Y を取得します。これは、アイテムの実際の原点であり、シーン座標で表されます 3) 子の位置を設定します

パイサイドで:

    br = parent.mapToScene(parent.boundingRect())
    realX = min([item.x() for item in br])
    realY = min([item.y() for item in br])
    child.setPos(parent.mapFromScene(realX, realY)) #modify according to need
于 2014-08-03T19:11:08.550 に答える