Map QWidget center position to QGraphicsScene coordinates?
-
I have a QGraphicsItem with an embedded QWidget, this QWidget have a QPushButton in it.
I'm trying to map the center of the QPushButton to the QGraphicsScene coordinates, so for example, I can add a Circle to the center of the QPushButton.With the help from another post I was able to find the center of the QPushButton, but it doesn't correspond to its actual position in the QGraphicsScene.
What I tried:
-
Getting the QRect of the button and then its center, finally mapping to the global coordinates of the view.
-
Getting the QRect of the button, then its center and mapping it to the QGraphicsItem.
-
Getting the QRect of the button, then its center, mapping it to the QGraphicsItem and than mapping it to the scene.
In general, I tried mapping it to Scene, to Global and to Item but it always looks incorrect. And the farther I move the QGraphicsItem, the less accurate it gets. Here the circle is supposed to be positioned at the center of the "B" button:
Qwidget:
class NodeFrame : public QFrame { public: NodeFrame(); QRect getButtonRect() { return layout->itemAt(0)->geometry(); } private: QPushButton* button = nullptr; QHBoxLayout* layout = nullptr; }; NodeFrame::NodeFrame() { setFixedSize(200,80); // Creates and add a QPushButton to the frame. // I need the position of this button on the QGraohicsScene button = new QPushButton("B"); button->setFixedSize(40,20); layout = new QHBoxLayout(); layout->addWidget(button); layout->setAlignment(Qt::AlignCenter); setLayout(layout); }
QGraphicsItem:
class Node : public QGraphicsItem { public: Node(); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; QRect getButtonRect() { return frame->getButtonRect(); } NodeFrame* frame = nullptr; }; Node::Node() { setFlag(ItemIsMovable); // Create a GraphicsProxyWidget to insert the nodeFrame into the scene auto proxyWidget = new QGraphicsProxyWidget(this); frame = new NodeFrame(); proxyWidget->setWidget(frame); // Center the widget(frame) at the center of the QGraphicsItem proxyWidget->setPos(boundingRect().center() - proxyWidget->boundingRect().center()); } QRectF Node::boundingRect() const { return QRectF(-10, -10, 280, 150); } void Node::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { QPainterPath path; path.addRoundedRect(boundingRect(), 10, 10); painter->drawPath(path); }
main:
int main(int argc, char* argv[]) { QApplication app(argc, argv); // Create scene and view auto scene = new QGraphicsScene(); auto view = new QGraphicsView(scene); view->setMinimumSize(800, 800); // Create the QGraphicsItem and add it to the scene auto item = new Node(); scene->addItem(item); item->setPos(50, 50); auto btnRect = item->getButtonRect(); auto center = view->mapToGlobal(btnRect.center()); auto circle = new QGraphicsEllipseItem(); circle->setRect(QRectF(center.x(), center.y(), 25, 25)); scene->addItem(circle); // Show the the view view->show(); return app.exec(); }
Appreciate any help.
-
-
@Tacc
So far as I recall: rather than maintain quite unrelated, separate items, don't you want to make the widget a child of theQGraphicsItem
--- that means it is always on it and moves with it --- and then I think its position is relative to the (top left of the) graphics item (hence a "small" number, start from(0,0)
)? -
This is the output from qDebug():
NodeFrame: QPointF(208,29) Node::AnchorPoint: QPointF(208,29) Anchor: QPointF(208,29) Circle: QPointF(208,29)
Meaning that in all stages the position is the same. I would assume that the position of a widget inside a widget will not be same in a QGraphicsScene. But It doesn't really matter how I map it: To Item, to Scene, To Global... the output is always the same. I'm really lost here. This shouldn't be that hard. What Am I missing?
-
I made some progress. If I don't set the position on the QGraphicsItem at item->setPos(50, 50); the position of the getButtonRect() will be correct. So, it seems as this is returning the position relative to the scene. The output:
NodeFrame: QPointF(208,29) Node::AnchorPoint: QPointF(208,29) Anchor: QPointF(208,29) Circle: QPointF(208,29)
Is all relative to the center of the scene, not the item. Any ideas? I have been working on this for over a week. I have read to docs about QTransform and about the transformation system but I can't figure it out.
-
@Tacc
So far as I can see, you are showing some output ofQPointF
s but have never told us what method(s) you are using to get these, so how do we know?GraphicsItem
s have aQPointF pos()
in parent coordinates if parented or scene coordinates if not, and aQPointF scenePos()
in scene coordinates unconditionally. -
@JonB In my minimal example the method getButtonRect() in NodeFrame and Node are printing those outputs. Except
Anchor
andCircle
which are printed in main().NodeFrame::getButtonRect() gets the button widget geometry.
Node::getButtonRect() just calls NodeFrame::getButtonRect(). In both methods I added a qDebug() to print the center of the QRect returned by getButtonRect().The idea is that I have a button "B" inside a widget, then this widget is inserted into a scene using a QGraphicsItem with a Proxy. I need to get the position of the button in the scene. I need the position of the button, not the position of the QGraphicsItem.
-
@Tacc
It would not surprise me if you can only get as far as finding the geometry of theQGraphicsItem
on the scene. Then the button has geometry relative to the widget it is on. And you would have to calculate from that if you want to figure its scene geometry. Maybe that's what you're already trying to do, I don't know. -
@JonB I think I understand what is happening. I'm getting all those positions in the constructos of each item/widget. So the position is what is expected when I create them. However, once I move one of the element the result is not what I expect anymore because(of course) the constructor is not going to run again. Can you help me with that?
-
@Tacc said in Map QWidget center position to QGraphicsScene coordinates?:
I'm getting all those positions in the constructos of each item/widget.
That's why it's a shame that you did not show the code where you were printing the values. I did not know you were doing that.
Can you help me with that?
In what sense? If you move things and want to output their position, add a function you can call (e.g. from a menu item) while you develop/debug, or use something like QGraphicsItem::itemChange() or QGraphicsScene::changed() to recognise it has moved.