2012-07-12 22 views
7

私はQGraphicsItemの親であるQGraphicsTextItemを持っています。私はQGraphicsTextItemが常にQGraphicsItemのすぐ上に存在するようにしたいが、スケールファクタが1より小さくなるとテキストを同じサイズにしたい、つまり親グラフィックスアイテムの縮尺が小さくなりました。スケールファクタが1未満のときにQGraphicsItem::ItemIgnoresTransformationsフラグをtrueに設定すると、サイズを保持するためのトリックが行われることがわかりました。QGraphicsItem :: ItemIgnoresTransformationsを適用した後の相対的な子の位置を維持する

しかし、QGraphicsItemの上に常に置かれるテキストの位置を取得する方法を見つけることができないようです。これを行う方法はありますか?私はdeviceTransform()関数を使ってみましたが、スクロールしてもQGraphicsItemのテキストはまだ動き出しました。さらに悪いのは、テキスト項目の一部が「ジグリング」し始めたことです。つまり、彼らは揺れているように見えるように、位置を少しずつ変え続けています。これが私が使用する必要のある機能であれば、正しく使用する方法はわからないと思います。

私はQGraphicsTextItemを追加しました私のQGraphicsItemのコンストラクタで

:これは何のためにやり過ぎかもしれ:ここでは

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); 
} 
+0

あなたはQGraphicsTextItemではなくQGraphicsItemの親変換を無視するようにフラグを設定するオブジェクトではないでしょうか? – ArmenB

答えて

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(); 
+0

この時点で私の問題のために過剰なもののように見えます:)しかし、簡単な方法がない場合、アプローチを固めます。どうもありがとう! – KD07

+0

私のアプリケーションでこのカスタム変換を使用しようとしました。それは遠い変換が懸念されているとしても、私のアイテムの位置はオフです。私は私の子供のアイテム(カスタム変換を持っている)が親の(0,0)ポイントにとどまりたい。私はsome_pointを(0,0)として渡します。 – KD07

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()); 
+0

KD07は 'QGraphicsTextItem'(HTML /リッチテキストフォーマットをサポートしています)について質問しました。 'QGraphicsSimpleTextItem'の別のテイクは、[Qt Center](http://www.qtcentre.org/threads/51168-QGraphicsTextItem-center-based-coordinates)にあります。 – handle

0

Dave Mateerの答えに加えて、あるシナリオでは、オブジェクトの適切な境界矩形(形状だけでなく)も維持する必要があると付け加えれば助かります。私にとっては、boundingRect()を少し変更して、適切なオブジェクト選択の動作をさせる必要があります。 ItemIgnoresTransformationsフラグを使用しない場合、オブジェクトの境界矩形は通常のように拡大縮小され、変換されることに注意してください。したがって、ビューの独立性を維持するためにboundingRectのサイズを変更する必要もあります。

ビューに依存しない境界矩形を維持するには、非常に簡単です。スケーリング係数をdeviceTransform(m_view->viewportTransform()).inverted().m11()から取得し、この定数にローカル座標の境界矩形を掛けます。例:

qreal m = this->deviceTransform(m_view->viewportTransform()).inverted().m11(); 
return QRectF(m*(m_shapeX), m*(m_shapeY), 
       m*(m_shapeR), m*(m_shapeR)); 
0

Dave Mateerの偉大な答え!さまざまなズームレベルで異なる倍率を定義したかったという問題がありました。これは私がそれをやった方法です:

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; 
} 

このソリューションによりアイテムが私の場合には非常にうまく機能します。ここ

0

は、私は非常に緩やかな複雑で考案されたソリューションです:

1)親のboundingRect()を取得し、シーン 2にマップ)ポイントのリストの最小値XとYを取り、このPysideで子供

の位置を設定する)シーンで 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 
0

私は任意の変換をいじったり伴わない別の解決策を、見つけました〜によって手スケーリング/位置決め。ヒントは、QGraphicsItem::ItemIgnoresTransformationsフラグの説明である:

QGraphicsItem::ItemIgnoresTransformations

アイテムが継承変換を無視する(すなわち、その位置はまだ親が、親またはビューの回転、ズームまたは に 固定されていますせん断変形は無視される)。 [...]

そして、それは重要なのです! (設定されているすべてのフラグ無し)の相対位置を維持します親と親の(0,0)で描画を行います子アイテム(QGraphicsItem::ItemIgnoresTransformationsフラグが設定されている)ポイント:我々は2つのアイテムが必要です。そのような単純な!

私は、単一のクラスにこの機能をカプセル化してきました - ここではいくつかのコードです:

#include <QGraphicsItem> 
#include <QPainter> 

class SampleShape : public QGraphicsItem 
{ 
private: 
    /* This class implements shape drawing */ 
    class SampleShapeImpl : public QGraphicsItem 
    { 
    public: 
     SampleShapeImpl (qreal len, QGraphicsItem *parent = nullptr) 
      : QGraphicsItem(parent), m_len(len) 
     { 
      /* ignore transformations (!) */ 
      setFlag(QGraphicsItem::ItemIgnoresTransformations); 
     } 

     QRectF boundingRect (void) const override 
     { 
      /* sample bounding rectangle */ 
      return QRectF(-m_len, -m_len, m_len*2, m_len*2); 
     } 

     void paint (QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override 
     { 
      /* draw a shape, (0,0) is an anchor */ 
      painter->drawLine(0, -m_len, 0, m_len); 
      painter->drawLine(-m_len, 0, m_len, 0); 
      // ... 
     } 

    private: 
     qreal m_len; // sample shape parameter 
    }; 

public: 
    /* This is actually almost an empty class, you only need to set 
    * a position and pass any parameters to a SampleShapeImpl class. 
    */ 
    SampleShape (qreal x, qreal y, qreal len, QGraphicsItem *parent = nullptr) 
     : QGraphicsItem(parent), m_impl(len, this) // <-- IMPORTANT!!! 
    { 
     /* set position at (x, y), view transformations will apply */ 
     setPos(x, y); 
    } 

    QRectF boundingRect (void) const override 
    { 
     return QRectF(); // it's just a point, no size 
    } 

    void paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override 
    { 
     // empty, drawing is done in SampleShapeImpl 
    } 

private: 
    SampleShapeImpl m_impl; 
}; 
関連する問題