QGraphicsScene::scenePos().toPoint() behaviour
-
I have experienced a weird behaviour in QGraphicsScene
Background:
Programm creates a Part of a roof. You can put modules on this roof. If you want you can save this state as a XML file.
Saving and loading works good.
But if you add new Modules on it, it "forgets" the position of the old modules, except if you move them, than the new Position is saved.But in the case you just want to add one or two Modules without moving the old ones. The item->scenePos().toPoint() will return x=0,y=0;
void RoofTab::onAddClick() { int width = qobject_cast<QLineEdit*>(this->widgets.value("tb_width"))->text().toInt(); int height = qobject_cast<QLineEdit*>(this->widgets.value("tb_height"))->text().toInt(); short type = qobject_cast<QComboBox*>(this->widgets.value("cbType"))->currentIndex(); //auto colour = qobject_cast<WidgetColorPicker*>(this->widgets.value("cp_string"))->getColor(); auto colour = QColor(qobject_cast<QComboBox*>(this->widgets.value("cbcolour"))->currentText()); auto stringNo = qobject_cast<QLineEdit*>(this->widgets.value("tb_string"))->text().toUInt(); auto manu = qobject_cast<QLineEdit*>(this->widgets.value("tb_manufacteurer"))->text(); auto model = qobject_cast<QLineEdit*>(this->widgets.value("tb_model"))->text(); uint64_t watt = qobject_cast<QLineEdit*>(this->widgets.value("tb_watt"))->text().toUInt(); CPVModulItem* item = [&]() { if (type == 0) return new CPVModulItem(0, 0, width, height); return new CPVModulItem(0, 0, height, width); }(); item->setFlags(QGraphicsItem::GraphicsItemFlag::ItemIsSelectable | QGraphicsItem::GraphicsItemFlag::ItemIsFocusable | QGraphicsItem::GraphicsItemFlag::ItemIsMovable); item->setBrush(QBrush(colour)); item->setHeight(height); item->setWidth(width); item->setStringNo(stringNo); item->setManufacteurer(manu); item->setModel(model); item->setWatt(watt); connect(item, &CPVModulItem::RightClick, this, &RoofTab::onPVContextMenu); connect(item, &CPVModulItem::DelPress, this, [&](CPVModulItem* sender) { if (QMessageBox::question(nullptr, QString::fromStdU32String(lang[rt]["DelQuestion"]["title"]), QString::fromStdU32String(lang[rt]["DelQuestion"]["body"]), QMessageBox::StandardButton::Yes, QMessageBox::StandardButton::No) == QMessageBox::StandardButton::Yes) { this->mScene->removeItem(sender); } }); connect(item, &CPVModulItem::ArrowKey, this, &RoofTab::ArroyKeyPress); this->mScene->addItem(item); } void RoofTab::addModule(const QPoint& pos, const QColor& colour, const Details& details) { auto* el = new CPVModulItem(pos.x(), pos.y(), details.width, details.height); el->setFlags(QGraphicsItem::GraphicsItemFlag::ItemIsSelectable | QGraphicsItem::GraphicsItemFlag::ItemIsFocusable | QGraphicsItem::GraphicsItemFlag::ItemIsMovable); el->setBrush(colour); el->setWatt(details.Watt); el->setManufacteurer(details.manufacteurer); el->setModel(details.Model); el->setWidth(details.width); el->setHeight(details.height); el->setStringNo(details.string_no); connect(el, &CPVModulItem::RightClick, this, &RoofTab::onPVContextMenu); connect(el, &CPVModulItem::DelPress, this, [&](CPVModulItem* sender) { if (QMessageBox::question(nullptr, QString::fromStdU32String(lang[rt]["DelQuestion"]["title"]), QString::fromStdU32String(lang[rt]["DelQuestion"]["body"]), QMessageBox::StandardButton::Yes, QMessageBox::StandardButton::No) == QMessageBox::StandardButton::Yes) { this->mScene->removeItem(sender); } }); connect(el, &CPVModulItem::ArrowKey, this, &RoofTab::ArroyKeyPress); this->mScene->addItem(el); }
onAddClick() is in case you add Modules via Signal/Slot
addModule is used to load the Module from XML.I am confused that the position is not saved :O
EDIT:
The Constructor of CPVModuleItem is:CPVModulItem::CPVModulItem(qreal x, qreal y, qreal width, qreal height, bool portrait, QGraphicsItem* parent) : QGraphicsRectItem(x, y, width, height, parent), backup_position(x,y) { }
-
@SeppyQT said in QGraphicsScene::scenePos().toPoint() behaviour:
But in the case you just want to add one or two Modules without moving the old ones. The item->scenePos().toPoint() will return x=0,y=0;
At first glance, I would say it's an update issue (of your scene or your items). What are the x / y values directly after you add a new item to your scene? Do all items appear at the correct coordinates? What does the XML file look like if you add items and save them?
What isbackup_position(x, y)
for?@SeppyQT said in QGraphicsScene::scenePos().toPoint() behaviour:
auto* el = new CPVModulItem(pos.x(), pos.y(), details.width, details.height);
what does
pos.x()
pos.y()
return here?@SeppyQT said in QGraphicsScene::scenePos().toPoint() behaviour:
CPVModulItem* item = & {
if (type == 0)
return new CPVModulItem(0, 0, width, height);
return new CPVModulItem(0, 0, height, width);
}();Of course it's (0/0), because you passed (0/0)
-
after loading all Items are placed correctly.
auto* el = new CPVModulItem(pos.x(), pos.y(), details.width, details.height,this->getScene()); auto temp = el->scenePos().toPoint();
temp is x=0,y=0
and backup_position was for debugging earlier.
@Pl45m4 said in QGraphicsScene::scenePos().toPoint() behaviour:
Of course it's (0/0), because you passed (0/0)
the mentioned function is to add a new Module. You move the item later with the mouse to the wanted position.
I could bypass the wierd thing with using backup_position and save the new Position as
auto bp = element->getBackupPosition(); auto np = element->scenePos().toPoint(); //np = new Position QPoint pos((bp.x()+np.x()),(bp.y()+np.y());
with that it saves the correct position of both old modules and new inserted modules.
-
@SeppyQT said in QGraphicsScene::scenePos().toPoint() behaviour:
You move the item later with the mouse to the wanted position
So if you add a new item / modul, it appears at the top left corner (0/0) first before you can move it by dragging to the correct position?!
Do you call
setPos(x, y)
when you move your item with your mouse? Since yourCPVModulItem
inherits fromQGraphicsRectItem
which inheritsQGraphicsItem
, you need to update it's position by callingsetPos(x, y)
, otherwise yourCPVModulItem
x and y will return the initial values, which are 0. Moving the item can cause the scene to update, so the position values get set and you get the updated (and correct) coords afterwardsShow your
mouseMoveEvent
please or the part where you move your item(s). -
@Pl45m4 said in QGraphicsScene::scenePos().toPoint() behaviour:
So if you add a new item / modul, it appears at the top left corner (0/0) first before you can move it by dragging to the correct position?!
yes you are right. if you add a new item it will appear top left corner.
so I need to overload keyReleaseEvent for setPos ?
but why does it save the new Modules correctly but not the old ones? -
@SeppyQT said in QGraphicsScene::scenePos().toPoint() behaviour:
so I need to overload keyReleaseEvent for setPos ?
You could either do that or you update on
mouseMove
.You could also add something like a
bool mouseDownOnItem
member to your item class (but it's pretty much the same as reacting onQGraphicsItem
smousePressEvent
ormouseReleaseEvent
directly@SeppyQT said in QGraphicsScene::scenePos().toPoint() behaviour:
but why does it save the new Modules correctly but not the old ones
Adding a new object to your scene will cause a repaint / update. So it updates existing items. Otherwise your items keep their initial values and
item->pos()
will return (0/0), because you didnt pass the actual position to your items base class (which isQGraphicsRectItem
, which is aQGraphicsItem
)Have a look at this (https://forum.qt.io/topic/49388/qgraphicsitem-mouse-press-event-return)