QTシーンビューで、2Dグラフィック項目がQGraphicsItemがあり、我々は、継承を通じて私たち自身のグラフィックアイテムを定義することができます。
主に以下の3つの仮想機能に焦点を当てる必要があります。
1)外接矩形(実装されなければなりません)
仮想QRectF boundingRect()のconst = 0;
2)パターン形状(別の実装)、関数は、デフォルトの実装がboundingRect矩形(特定のアイテムの形状パターンを任意に変更され、デフォルト値を返し、等一般的衝突検出に使用されるパスグラフィック項目、ヒットテストを、実際の形状を返します長方形の形状を正しく図形の実際の形状を表すものでは明らかに、)機能を書き換えることが提案されています。なお、輪郭線の形状は、ブラシのサイズ、および線形に依存して変化し得るので、領域の実際の形状は、輪郭が含まれるべきです。
仮想QPainterPathの形状()constは、
3)グラフィック・コンテンツ(実装されなければなりません)
仮想ボイドペイント(QPainterの*画家、 constのQStyleOptionGraphicsItem *オプション、 QWidgetの*ウィジェット= nullptr)= 0;
二つの一般的な形でパターン:ブロッキングと非ブロッキング、例えば直線、曲線などの非ブロッキングパターンとして、長方形、楕円形の閉パターン、領域の実際の形状は線路として指定、非閉じた形状を充填するために使用することができません、閉パターンを充填するために使用することができ、実際の形状はラインを含み、充填領域を閉じます。
QT QPainterのクラスは、不規則な形状のいくつかの複雑なパターンのために、(例えば、矩形、楕円、多角形、テキスト、等)をレンダリングする最も一般的なグラフィックスAPIを提供するパスを描くことによって達成方法drawPathを提供します。
QPainterPath
QPainterPathクラス(描画パス)は描画操作のための容器を提供し、再利用パターン形状を作成することができます。
矩形、楕円、直線と曲線:例えば、からなる多くのグラフィカルなビルディングブロックからなるパスオブジェクトを描画します。ビルディングブロックは、例えば、閉鎖サブ経路で添加することができる:長方形または楕円形。開始および閉路の端同じであるか、非独立したサブパスが存在するように彼らのような、封入されてもよい:直線と曲線。
図面と比較すると、主な利点は、そのQPainterPathです:一度作成した複雑なグラフィックは、単に多くの回を描画するためにQPainterの:: drawPath()関数を呼び出します。QPainterPath要素を描画情報や経路を得るために使用することができる機能のセットを提供します。要素の順序を変更するtoReversed()関数を使用することに加えて、QPainterPathポリゴンにオブジェクトを変換するためのいくつかの機能があります。
QPainterPathStroker
QPainterPathは、アウトライン(輪郭)、カット(クリップ)をトレース、(充填)に充填することができます。指定された描画パスに充填することができる輪郭を生成するには、QPainterPathStrokerクラスを使用することができます。。
createStroke()関数を呼び出すことによって、与えられたQPainterPathがパラメータとして渡された、新しいパスを作成するアーティストは、指定されたパスの輪郭(outlinepath)を表しています。画家は、その後の元の画家パス(パス)を輪郭のために新たに作成されたパスを埋めることができます。
様々なデザイン(ペン幅、スタイルキャップ、及びパターンモードを結ぶ点線)あなたがコントロール輪郭の以下の機能を使用することができます。
- setWidth()
- setCapStyle()
- setJoinStyle()
- setDashPattern()
Qtの:: PenStyleオブジェクトを受信することができるsetDashPattern()関数は、ベクトルパターンに許容可能なパラメータとして表すことができます。
また、あなたがsetCurveThreshold()関数は指定された閾値曲線を使用することができ、粒子サイズの制御は、プロットしました。デフォルトのしきい値は良い調整(0.25)の値であり、通常、あなたがそれを変更する必要はありません。しかし、あなたはスムーズなの値を減らすことにより、曲線の外観を作ることができます。
またsetMiterLimit()関数マイターリミットは、輪郭の生成を制御し使用することができます。説明マイターリミットマイターは、各接続の距離まで延びていてもよいです。限界は、幅の単位で指定し、したがってマイター限度の画素は*幅をmiterLimitのであろう。接続のスタイルは、Qtのある場合のみ、:: MiterJoinは、この値を使用します。
注、createStroke()関数は、唯一の画家・パスを生成するために使用することができ、それ以外の場合は、予期しない動作を引き起こす可能性があり、与えられた画家の道を概説。アウトラインは、デフォルトのQt :: WindingFillルールセットを生成する必要があります。
正確な2Dグラフィックスを拾う達成するためのQTシーンビュー、あなたはむしろboundingRectよりグラフィック形状に焦点を当てる必要があります、以下は参照用のテストケースであります:
QGraphicsItem、いくつかの一般的な行動のサブ項目のための引当金から継承された新ItemBaseクラス、:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#ifndef
ITEMBASE_H #define ITEMBASE_H #include <QGraphicsItem> class QGraphicsSceneMouseEvent; class ItemBase : public QGraphicsItem { public : ItemBase(QSize size, QGraphicsItem *parent = nullptr); virtual ~ItemBase() override; QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected : void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void wheelEvent(QGraphicsSceneWheelEvent *event) override; bool isInResizeArea( const QPointF &pos); protected : QSize m_size; private : bool m_isResizing; bool m_isRotating; }; #endif // ITEMBASE_H |
在ItemBase类中,我们重写了boundingRect以及paint函数,图形项的具体形状在子类中重写shape()来实现:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
QRectF ItemBase::boundingRect()
const
{ // 实际图形形状的边界矩形 return shape().boundingRect(); } void ItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(widget); if (option->state & QStyle::State_Selected) { painter->setRenderHint(QPainter::Antialiasing, true ); if (option->state & QStyle::State_HasFocus) { painter->setPen(QPen(Qt::yellow, 3 )); } else { painter->setPen(Qt::white); } painter->drawRect(boundingRect()); } painter->setRenderHint(QPainter::Antialiasing, false ); } |
以ItemPolyline为例进行说明:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#ifndef
ITEMPOLYLINE_H #define ITEMPOLYLINE_H #include "ItemBase.h" class ItemPolyline : public ItemBase { public : ItemPolyline(QSize size, QGraphicsItem *parent = nullptr); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr); // overwrite shape() QPainterPath shape() const ; }; #endif // ITEMPOLYLINE_H #include "ItemPolyline.h" #include <QPainter> #include <QPainterPath> ItemPolyline::ItemPolyline(QSize size, QGraphicsItem *parent) : ItemBase (size, parent) { } void ItemPolyline::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { static const QPointF points[ 3 ] = { QPointF( 10 . 0 , 100 . 0 ), QPointF( 20 . 0 , 10 . 0 ), QPointF( 100 . 0 , 30 . 0 ), }; painter->save(); QPen pen(Qt::blue); pen.setWidth( 10 ); pen.setJoinStyle(Qt::MiterJoin); // MiterJoin, BevelJoin, RoundJoin pen.setCapStyle(Qt::RoundCap); // FlatCap, SquareCap, RoundCap pen.setStyle(Qt::DashLine); painter->setPen(pen); painter->drawPolyline(points, 3 ); painter->restore(); ItemBase::paint(painter, option, widget); } QPainterPath ItemPolyline::shape() const { static const QPointF points[ 3 ] = { QPointF( 10 . 0 , 100 . 0 ), QPointF( 20 . 0 , 10 . 0 ), QPointF( 100 . 0 , 30 . 0 ), }; QPainterPath path; path.moveTo(points[ 0 ]); path.lineTo(points[ 1 ]); path.lineTo(points[ 2 ]); QPainterPathStroker stroker; stroker.setWidth( 10 ); stroker.setJoinStyle(Qt::MiterJoin); stroker.setCapStyle(Qt::RoundCap); stroker.setDashPattern(Qt::DashLine); return stroker.createStroke(path); } |
ItemPolyline类中重写shape()函数,使用QPainterPath和QPainterPathStroker比较精准地获取了图形的轮廓形状,有利于鼠标对图形的精准拾取。
除了Polyline外,我还做了Rectangle、Ellipse、Bezier、ClosedBezier以及line和lines等2D图形,以下是运行截图:
鼠标点击2D图形的有效区域(即Shape所规定的路径区域)会比较精准地选中图形,而其它空白区域则无法选中,仅供参考,欢迎交流!