Reputation: 53
I'm writing a program that should create a QGraphicsItem when a double-click happens (inside the scene area), and also that item must be created at double-click position. I've already written some code, but it doesn't work properly. When I double-click on the scene, an item gets created, but at a completely different place. So right now that is the problem. I need it to be created at mouse's position.
Here is my code:
ui_path = "C:/Users/User/Desktop/programming/Creator/Creator.ui"
class Creator(QtWidgets.QWidget):
count = 0
def __init__(self):
super(Creator, self).__init__()
loader = QtUiTools.QUiLoader()
self.ui = loader.load(ui_path, self)
self.variables()
self.ui.canvas_area.viewport().installEventFilter(self) #canvas_area is the QGraphicsView
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint)
def variables(self):
self.scene = QtWidgets.QGraphicsScene()
self.ui.canvas_area.setScene(self.scene)
def eventFilter(self, obj, event):
if obj is self.ui.canvas_area.viewport():
if event.type() == QtCore.QEvent.MouseButtonDblClick:
self.createItems(event)
return super(Creator, self).eventFilter(obj, event)
def createItems(self, event):
pos = event.pos()
self._x = pos.x()
self._y = pos.y()
rect = self.scene.addRect(self._x, self._y, 40, 40, QPen(Qt.red), QBrush(Qt.gray))
rect.setFlag(QGraphicsItem.ItemIsMovable)
rect.setFlag(QGraphicsItem.ItemIsFocusable)
rect.setFlag(QGraphicsItem.ItemIsSelectable)
if __name__ == '__main__':
creator_window = Creator()
creator_window.ui.show()
I've read something about mapFromScene and mapToScene, and that these can solve the problem - but I don't really understand how to use them. Also there are some examples of this, but all that I've found were in C++, which I know nothing about. So if someone could help me figure out how to solve this problem I would really appreciate that.
Upvotes: 1
Views: 490
Reputation: 120578
You first must set the scene-rect for the scene:
self.scene.setSceneRect(0, 0, 1000, 1000)
then you must convert the event position to scene co-ordinates, like this:
pos = self.canvas_area.mapToScene(event.pos())
and that should be all that's needed to fix your example.
A different approach that may be worth considering would be to install an event-filter on the scene instead:
self.scene.installEventFilter(self)
and then filter on the more specialised graphics events:
def eventFilter(self, obj, event):
if obj is self.scene:
if event.type() == QtCore.QEvent.GraphicsSceneMouseDoubleClick:
self.createItems(event)
return super(Creator, self).eventFilter(obj, event)
This creates a QGraphicsSceneMouseEvent, which has several useful features that a standard QMouseEvent doesn't have. This includes scenePos(), which saves having to map to scene co-ordinates all the time, allowing you to then simply do:
pos = event.scenePos()
Upvotes: 2