Qt insert QGraphicsItem in scene on click position

201 Views Asked by At

I am designing an app to draw electrical circuit models and I need to insert elements on scene by clicking on a button and after on the scene.

The way it should work is the following: I press the button to insert a node, then it shows a message saying "Press where you want to insert the element", you press, and the element appear on screen.

I think the problem is that I have to stop the code to get the position and then continue or something like that.

Below I show a part of the code (the original contains more classes and a second tab for calculations, that it is not needed for this trouble and it is not connected in any way):

from PyQt5 import sip
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import QRectF, Qt, QSize, QPointF, QPoint, QLineF, showbase
from PIL import Image
import calculation


class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Nodal Equations")
        self.setWindowIcon(QIcon("images/flash.ico"))
        self.setGeometry(150,50,1650,950)
        self.setFixedSize(self.size())

        self.UI()
        self.show()

    def UI(self):
        self.toolBar()
        self.tabwidgets()
        self.widgets()
        self.layouts()


    def toolBar(self):
        self.tb = QToolBar("Toolbar")
        self.addToolBar(Qt.RightToolBarArea, self.tb)
        self.tb.setIconSize(QSize(50,50))

        # Toolbar buttons
        self.addNode = QAction(QIcon("images/node.png"),"Node",self)
        self.tb.addAction(self.addNode)
        self.addNode.triggered.connect(self.funcAddNode)
        self.tb.addSeparator()



    def tabwidgets(self):
        self.tabs = QTabWidget()
        self.tabs.blockSignals(True) # To update tabs. After defining every layout we have to set it to False
        self.setCentralWidget(self.tabs) # If this is not used, we cannot see the widgets (Needed if we use QMainWindow)
        self.modelViewTab = QWidget()
        self.tabs.addTab(self.modelViewTab, "Model View")

    def widgets(self):
        # Model View widgets
        self.view = ModelView()
        self.instructionsLabel = QLabel("Welcome to Node Equations Solver. To start select an order on the toolbar menu", self)


    def layouts(self):
        # Model View Tab layouts
        self.mainModelLayout = QVBoxLayout()
        self.sceneLayout = QHBoxLayout()
        self.instructionsLayout = QHBoxLayout()
        self.mainModelLayout.setAlignment(Qt.AlignCenter)

        ##### Adding widgets
        self.sceneLayout.addWidget(self.view)

        self.instructionsLayout.addWidget(self.instructionsLabel)

        ##### Adding layouts
        self.mainModelLayout.addLayout(self.sceneLayout)
        self.mainModelLayout.addLayout(self.instructionsLayout)

        self.modelViewTab.setLayout(self.mainModelLayout)
        

    def funcAddNode(self):
        self.node = Node(0,500,500)
        self.view.scene.addItem(self.node)


class Node(QGraphicsEllipseItem):
    def __init__(self,number, x, y):
        super(Node, self).__init__(0, 0, 10, 10)
        self.number = number

        self.setPos(x, y)
        self.setBrush(Qt.yellow)
        self.setAcceptHoverEvents(True)

    # Mouse hover events
    def hoverEnterEvent(self, event):
        app.instance().setOverrideCursor(Qt.OpenHandCursor)

    def hoverLeaveEvent(self, event):
        app.instance().restoreOverrideCursor()

    # Mouse click events
    def mousePressEvent(self, event):
        app.instance().setOverrideCursor(Qt.ClosedHandCursor)

    def mouseReleaseEvent(self, event):
        app.instance().restoreOverrideCursor()

    def mouseMoveEvent(self, event):
        orig_cursor_position = event.lastScenePos()
        updated_cursor_position = event.scenePos()

        orig_position = self.scenePos()

        updated_cursor_x = updated_cursor_position.x() - orig_cursor_position.x() + orig_position.x() 
        updated_cursor_y = updated_cursor_position.y() - orig_cursor_position.y() + orig_position.y() 
        if updated_cursor_x < 0:
            self.setPos(QPointF(0, updated_cursor_y))
        elif updated_cursor_y < 0:
            self.setPos(QPointF(updated_cursor_x, 0))
        elif updated_cursor_x + self.boundingRect().right() > 1550:
            self.setPos(QPointF(1550 - self.boundingRect().width(), updated_cursor_y))
        elif updated_cursor_y + self.boundingRect().bottom() > 840:
            self.setPos(QPointF(updated_cursor_x, 840 - self.boundingRect().height()))
        else:
            self.setPos(QPointF(updated_cursor_x, updated_cursor_y))





class ModelView(QGraphicsView):
    def __init__(self):
        super().__init__()

        self.setRenderHints(QPainter.Antialiasing)

        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.setSceneRect(0, 0, 1550, 840)

    ##### This is a way I tried to pick the cursor position and store it, but it didn't work
    # def mousePressEvent(self, event):
    #     x = event.scenePos().x()
    #     y = event.scenePos().y()
        
    #     return (x,y)


def main():
    global app
    app = QApplication(sys.argv)
    window = Main()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
1

There are 1 best solutions below

1
SebDieBln On

You need to change the return (x,y) to something useful, i.e. emitting a signal or actually adding an element.

mousePressEvent is a method that does not return anything (void in C++).