2016-10-20 3 views
2

Ich habe eine Klasse von QGraphicsEllipseItem abgeleitet, in der ich wissen muss, wenn sich ihre Position oder Größe in irgendeiner Weise ändert. Ich handle die Größenänderung mit einer Maus und rufe QGraphicsEllipse :: setRect auf.QGraphicsItem :: itemChange wird für Positionsänderung, aber nicht für Größenänderung benachrichtigt

OK, so überwog ich pflichtschuldigst die itemChange() -Methode in der Klasse und dann war vorsichtig, um die ItemSendsGeometryChanges Flag zu setzen, nach dem Erstellen es

// Returns a human readable string for any GraphicsItemChange enum value 

inline std::string EnumName(QGraphicsItem::GraphicsItemChange e); 

// Simple test ellipse class 

class MyEllipse : public QGraphicsEllipseItem 
{ 
public: 
    MyEllipse(int x, int y, int w, int h) : QGraphicsEllipseItem(x, y, w, h) 
    { 
     setFlags(
      QGraphicsItem::ItemIsSelectable 
      | QGraphicsItem::ItemIsMovable 
      | QGraphicsItem::ItemSendsGeometryChanges); 
    } 


    // QGraphicItem overrides 
    virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override 
    { 
     std::stringstream oss; 
     oss << "ItemChange " << EnumName(change) << std::endl; 
     OutputDebugString(oss.str().c_str()); 
     return __super::itemChange(change, value); 
    } 
}; 

Mein Haupt Code erstellt eine davon, fügt sie die Szene und versucht dann, es zu verschieben/zu skalieren.

Und während ich immer nach dem Aufruf von SetPos() auf der Ellipse Benachrichtigungen erhalten, bekomme ich keine Benachrichtigung nach dem Aufruf von SetRect(). Ich kann setRect verwenden, um die Geometrie der Ellipse vollständig zu ändern, aber meine itemChange override wird nie aufgerufen. Nicht mit irgendwelchen Flaggen.

Nun ändert offensichtlich die Änderung der Geometrie des Gegenstandes seine Geometrie, also was fehlt mir?

Gibt es eine andere Flagge, die ich einstellen sollte? Eine andere Möglichkeit, die Größe der Ellipse zu ändern, die ich verwenden sollte? Einige andere Benachrichtigungen, die ich überschreiben kann?

+0

Zunächst ersten drei Zeilen Ihrer 'itemChange' zu' qDebug ausgetauscht werden können() << Änderung; '... Auf den zweiten, was' QGraphicsItem :: GraphicsItemChange' Wert erwarten Sie? Die nahesten Werte sind 'ItemTransformChange' und' ItemScaleChange', aber sie sind mit etwas anderem verbunden. Sie können versuchen, die Größe der Ellipse mit der Methode 'setTransform' zu ändern und eine davon zu erhalten. – ilotXXI

+0

Ich denke, ich erwarte, dass es einen Wert in GraphicsItemChange gibt, der dies abdeckt, da es eindeutig eine Änderung der Elementgeometrie ist, und ich setze speziell das Flag, um über Änderungen an dieser Geometrie benachrichtigt zu werden. Es scheint eine eklatante Lücke in dieser Benachrichtigung zu sein, wenn nur die Position des Objekts als Teil seiner Geometrie betrachtet wird. Ich kann die Ellipse nach Herzenslust verschieben, aber es scheint keine Möglichkeit zu geben, die Größe zu ändern und benachrichtigt zu werden – Joe

Antwort

1

Das Problem ist, dass QGraphicsItem 's Position nicht mit QGraphicsEllipseItem' s Rechteck verwandt ist. Die erste ist eine Position des Elements relativ zu seinem übergeordneten Element oder, wenn es NULL ist, zu seiner Szene. Die letzte ist ein Rechteck relativ zu der Position wo eine Ellipse gezeichnet werden soll. Die Szene und QGraphicsItem 's Kern wissen nichts über Änderungen davon.

Lassen Sie uns in diesem Test einen Blick:

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 

    QGraphicsScene scene; 
    QGraphicsView view(&scene); 
    QGraphicsEllipseItem item(10, 20, 30, 40); 
    scene.addItem(&item); 

    qDebug() << item.pos() << item.scenePos() << item.boundingRect(); 
    item.setRect(110, 120, 30, 40); 
    qDebug() << item.pos() << item.scenePos() << item.boundingRect(); 

    view.resize(500, 500); 
    view.show(); 

    return app.exec(); 
} 

Ausgang ist:

QPointF(0,0) QPointF(0,0) QRectF(9.5,19.5 31x41) 
QPointF(0,0) QPointF(0,0) QRectF(109.5,119.5 31x41) 

Mögliche Auswege:

  1. Verwendung setTransform. Änderungen der Transformationsmatrix werden vom Standard QGraphicsitems verfolgt, und itemChange erhalten die entsprechende Änderung. Aber ich denke, dass Nicht-Ident-Matrizen die Leistung verringern können (nicht überprüft).
  2. implementieren Sie Ihre eigene Funktion wie setRect, in denen Sie Geometrieänderungen manuell verfolgen.
  3. Unterklasse QGraphicsItem, nicht QGraphicsEllipseItem. In diesem Fall können Sie nicht verfolgbare Geometrieänderungen verhindern, da diese über Ihre Regeln ausgeführt werden. Es sieht wie folgt aus:

    class EllipseItem: public QGraphicsItem 
    { 
    public: 
        // Here are constructors and a lot of standard things for 
        // QGraphicsItem subclassing, see Qt Assistant. 
        ... 
    
        // This method is not related with QGraphicsEllipseItem at all. 
        void setRect(const QRectF &newRect) 
        { 
         setPos(newRect.topLeft()); 
         _width = newRect.width(); 
         _height = newRect.height(); 
         update(); 
        } 
    
        QRectF boundingRect() const override 
        { 
         return bRect(); 
        } 
    
        void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, 
           QWidget * widget = nullptr) override 
        { 
         painter->drawRect(bRect()); 
        } 
    
    private: 
        qreal _width; 
        qreal _height; 
    
        QRectF bRect() const 
        { 
         return QRectF(0, 0, _width, _height); 
        } 
    }; 
    

    Sie sollten auch Punkt-Transformationen und bewegt sich durch QGraphicsItem::itemChange verfolgen.

+0

Danke für die Antwort. Es scheint mir einfach keinen Sinn zu machen, dass ich über Änderungen an der Geometrie des Elements informiert werden könnte, und es ist so einfach, diese Geometrie zu ändern, ohne dass eine Benachrichtigung erfolgt. – Joe

+0

@Joe Wir haben was wir haben. :) Eine weitere Möglichkeit besteht darin, 'QGraphicsItem' abzuleiten und solche Methoden zu implementieren. Es ist einfach, eigene 'setRect' zu implementieren und niemand wird in diesem Fall" falsche "nicht-erkennbare Methoden aufrufen. – ilotXXI

+0

Ja, das ist im Grunde, was ich getan habe. Ich denke, es ist der C++ Purist/Worrier in mir. QGraphicsEllipseItem :: setRect ist nicht virtuell. Ich weiß nicht, was in QT vor sich geht. Ruft es diese Funktion jemals selbst an? Ich hoffe nicht, oder ich werde Löcher zu stecken haben ... – Joe

Verwandte Themen