Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The solution is to combine various things that you're already doing. Instrument <code>itemChange</code>, looking for and count the items with updated geometry. Once you've counted as many items as there are in the current selection, fire off a signal that will have everything ready for updating your status. Make sure you've set the <code>QGraphicsItem::ItemSendsGeometryChanges</code> flag on all your items! </p> <p>This code was edited to remove the lag inherent in using a zero-timer approach. Below is a <a href="http://sscce.org" rel="nofollow noreferrer">sscce</a> that demonstrates it.</p> <p>You create circles of random radius by clicking in the window. The selection is toggled with Ctrl-click or ⌘-click. When you move the items, a centroid diamond follows the centroid of the selected group. This gives a visual confirmation that the code does indeed work. When the selection is empty, the centroid is not displayed.</p> <p>I've gratuitously added code to show how to leverage Qt's property system so that the items can be generic and leverage the <code>notifier</code> property of a scene if it has one. In its absence, the items simply don't notify, and that's it.</p> <p><a href="https://i.stack.imgur.com/Y6omA.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Y6omA.png" alt="screenshot of the example"></a></p> <pre><code>// https://github.com/KubaO/stackoverflown/tree/master/questions/scenemod-11232425 #include &lt;QtWidgets&gt; const char kNotifier[] = "notifier"; class Notifier : public QObject { Q_OBJECT int m_count = {}; public: int count() const { return m_count; } void inc() { m_count ++; } void notify() { m_count = {}; emit notification(); } Q_SIGNAL void notification(); }; typedef QPointer&lt;Notifier&gt; NotifierPointer; Q_DECLARE_METATYPE(NotifierPointer) template &lt;typename T&gt; class NotifyingItem : public T { protected: QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &amp;value) override { QVariant v; if (change == T::ItemPositionHasChanged &amp;&amp; this-&gt;scene() &amp;&amp; (v=this-&gt;scene()-&gt;property(kNotifier)).isValid()) { auto notifier = v.value&lt;NotifierPointer&gt;(); notifier-&gt;inc(); if (notifier-&gt;count() &gt;= this-&gt;scene()-&gt;selectedItems().count()) { notifier-&gt;notify(); } } return T::itemChange(change, value); } }; // Note that all you need to make Circle a notifying item is to derive from // NotifyingItem&lt;basetype&gt;. class Circle : public NotifyingItem&lt;QGraphicsEllipseItem&gt; { QBrush m_brush; public: Circle(const QPointF &amp; c) : m_brush(Qt::lightGray) { const qreal r = 10.0 + (50.0*qrand())/RAND_MAX; setRect({-r, -r, 2.0*r, 2.0*r}); setPos(c); setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); setPen({Qt::red}); setBrush(m_brush); } }; class View : public QGraphicsView { Q_OBJECT QGraphicsScene scene; QGraphicsSimpleTextItem text; QGraphicsRectItem centroid{-5, -5, 10, 10}; Notifier notifier; int deltaCounter = {}; public: explicit View(QWidget *parent = {}); protected: Q_SLOT void gotUpdates(); void mousePressEvent(QMouseEvent *event) override; }; View::View(QWidget *parent) : QGraphicsView(parent) { centroid.hide(); centroid.setRotation(45.0); centroid.setPen({Qt::blue}); centroid.setZValue(2); scene.addItem(&amp;centroid); text.setPos(5, 470); text.setZValue(1); scene.addItem(&amp;text); setRenderHint(QPainter::Antialiasing); setScene(&amp;scene); setSceneRect(0,0,500,500); scene.setProperty(kNotifier, QVariant::fromValue(NotifierPointer(&amp;notifier))); connect(&amp;notifier, &amp;Notifier::notification, this, &amp;View::gotUpdates); connect(&amp;scene, &amp;QGraphicsScene::selectionChanged, &amp;notifier, &amp;Notifier::notification); } void View::gotUpdates() { if (scene.selectedItems().isEmpty()) { centroid.hide(); return; } centroid.show(); QPointF centroid; qreal area = {}; for (auto item : scene.selectedItems()) { const QRectF r = item-&gt;boundingRect(); const qreal a = r.width() * r.height(); centroid += item-&gt;pos() * a; area += a; } if (area &gt; 0) centroid /= area; auto st = QStringLiteral("delta #%1 with %2 items, centroid at %3, %4") .arg(deltaCounter++).arg(scene.selectedItems().count()) .arg(centroid.x(), 0, 'f', 1).arg(centroid.y(), 0, 'f', 1); this-&gt;centroid.setPos(centroid); text.setText(st); } void View::mousePressEvent(QMouseEvent *event) { const auto center = mapToScene(event-&gt;pos()); if (! scene.itemAt(center, {})) scene.addItem(new Circle{center}); QGraphicsView::mousePressEvent(event); } int main(int argc, char *argv[]) { QApplication app{argc, argv}; View v; v.show(); return app.exec(); } #include "main.moc" </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload