Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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)
    {
    }
    


  • EDIT 2:
    if you move the old ones you get only the length of the way the moved.
    if you move them one pixel right and down you will get x=1,y=1
    if you move left and up you will get x=-1,y=-1



  • @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 is backup_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 your CPVModulItem inherits from QGraphicsRectItem which inherits QGraphicsItem, you need to update it's position by calling setPos(x, y), otherwise your CPVModulItem 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 afterwards

    Show 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 on QGraphicsItems mousePressEvent or mouseReleaseEvent 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 is QGraphicsRectItem, which is a QGraphicsItem)

    Have a look at this (https://forum.qt.io/topic/49388/qgraphicsitem-mouse-press-event-return)


Log in to reply