Tuesday, 1 October 2019

Add objects asynchronously to QGraphicsScene

I develop an application where a lot of objects need to be added to a QGraphicsScene object in order to represent the diagram of an electric power system. When the grid is large this process takes a while and the main window remains unresponsive. Hence, I'd like to know a way to create the objects asynchronously.

The following code is an very very simplified version of the actual code. In the example I create objects and I add them to the scene using the function add_objects. This is the function that should run in a thread.

import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *


def add_objects(scene: QGraphicsScene, n=1000):
    for i in range(n):
        item = QGraphicsEllipseItem(i * 5, 10, 60, 40)
        scene.addItem(item)


class MyView(QGraphicsView):
    def __init__(self):
        QGraphicsView.__init__(self)

        self.setGeometry(QRect(100, 100, 600, 250))

        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(QRectF())

        self.setScene(self.scene)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    view = MyView()
    view.show()
    add_objects(scene=view.scene, n=100)
    sys.exit(app.exec_())

------ EDIT --------

Since I've been asked for another example, here goes the complete case:

import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from GridCal.Gui.GridEditorWidget import GridEditor
from GridCal.Engine.IO.file_handler import FileOpen


class AddObjectsThreaded(QThread):

    def __init__(self, editor: GridEditor, explode_factor=1.0):
        QThread.__init__(self)

        self.editor = editor

        self.explode_factor = explode_factor

    def run(self):
        """
        run the file open procedure
        """
        # clear all
        self.editor.diagramView.scene_.clear()

        # first create the buses
        for bus in self.editor.circuit.buses:
            bus.graphic_obj = self.editor.add_api_bus(bus, self.explode_factor)

        for branch in self.editor.circuit.branches:
            branch.graphic_obj = self.editor.add_api_branch(branch)

        # figure limits
        min_x = sys.maxsize
        min_y = sys.maxsize
        max_x = -sys.maxsize
        max_y = -sys.maxsize

        # Align lines
        for bus in self.editor.circuit.buses:
            bus.graphic_obj.arrange_children()
            # get the item position
            x = bus.graphic_obj.pos().x()
            y = bus.graphic_obj.pos().y()

            # compute the boundaries of the grid
            max_x = max(max_x, x)
            min_x = min(min_x, x)
            max_y = max(max_y, y)
            min_y = min(min_y, y)

        # set the figure limits
        self.editor.set_limits(min_x, max_x, min_y, max_y)
        #  center the view
        self.editor.center_nodes()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    fname = r'1354 Pegase.xlsx'  # this file you need to download from https://github.com/SanPen/GridCal/tree/master/Grids_and_profiles/grids
    circuit = FileOpen(fname).open()

    view = GridEditor(circuit)
    view.resize(600, 400)
    view.show()

    thr = AddObjectsThreaded(editor=view)
    thr.start()

    sys.exit(app.exec_())

This process crases cleanly with the following error:

Process finished with exit code -1073740791 (0xC0000409)



from Add objects asynchronously to QGraphicsScene

No comments:

Post a Comment