PyQt - display widget on top of widget

I am creating an application that displays a map of an area, and I'm trying to draw nodes on top of it that can represent information.

I did all of this, but did it simply by creating one custom widget that I showed and printed again and again each time the information changed. Also, I could not “connect” the nodes to the listeners, because they were just images in the original widget.

This made me want to reform my GUI, and now I'm trying to make each class a regular widget! But the problem is that my MapNodes are no longer displayed.

I searched stackoverflow and found this useful thread: How to set absolute position of widgets in qt

So, I have to provide the parent cards to the parents, and parent = the widget that is displayed (?)

Anyway, here is my throw by inserting the appropriate code here. Hint where things can go horribly wrong: all inits

app = QtGui.QApplication(list()) mutexbranch = Lock() mutexnode = Lock() def exec(): return app.exec_() #Singleton Pattern: wanneer en object aan iets moet kunnen # waar het inherent door de structuur niet aankon # wordt dit via dit singleton opgelost class GuiInternalCommunication: realmap = 0 class MapView(QtGui.QWidget, listener.Listener): def __init__(self, mapimagepath): QtGui.QMainWindow.__init__(self) listener.Listener.__init__(self) self.map = Map(self, mapimagepath) #self.setCentralWidget(self.map) self.initUI() def initUI(self): self.setWindowTitle('Population mapping') hbox = QtGui.QHBoxLayout() hbox.addWidget(self.map) self.setLayout(hbox) resolution = QtGui.QDesktopWidget().screenGeometry() self.setGeometry(20,20,550,800) self.show() ###################################################################### class Map(QtGui.QWidget): def __init__(self, parent, mapimagepath): QtGui.QWidget.__init__(self, parent) #self.timer = QtCore.QBasicTimer() #coordinaten hoeken NE en SW voor kaart in map graphics van SKO self.realmap = RealMap( mapimagepath, (51.0442, 3.7268), (51.0405, 3.7242), 550, 800) GuiInternalCommunication.realmap = self.realmap self.needsupdate = True self.timelabel = 0 parent.setGeometry(0,0,self.realmap.width, self.realmap.height) self.mapNodes = {} self.mapBranches = {} def paintEvent(self, event): painter = QtGui.QPainter() painter.begin(self) rect = self.contentsRect() #teken achtergrond self.realmap.drawRealMap(painter) #teken branches mutexbranch.acquire() try: for branch, mapBranch in self.mapBranches.items(): mapBranch.drawMapBranch(painter) finally: mutexbranch.release() ###################################################################### class RealMap(QtGui.QWidget): def __init__(self, path, coordRightTop, coordLeftBot, width, height, pixpermet = 2.6): super(RealMap, self).__init__() self.path = path self.mapimage = QtGui.QImage(self.path) self.coordLeftBot = coordLeftBot self.coordRightTop = coordRightTop self.width = width self.height = height self.realdim = self.calcRealDim() self.pixpermet = pixpermet def paintEvent(self, e): painter = QtGui.QPainter() painter.begin(self) self.drawRealMap(self, painter) painter.end() def drawRealMap(self, painter): painter.drawImage(0,0,self.mapimage) ###################################################################### class MapNode(QtGui.QWidget): dangertocolor = {"normal":"graphics//gradients//green.png", "elevated":"graphics//gradients//orange.png", "danger":"graphics//gradients//red.png"} gradimage = {"normal":QtGui.QImage(dangertocolor["normal"]), "elevated":QtGui.QImage(dangertocolor["elevated"]), "danger":QtGui.QImage(dangertocolor["danger"])} btimage = QtGui.QImage("graphics//BT-icon.png") def __init__(self, scanner, x, y, danger = 0, parent = None): # MapNode erft over van QWidget super(MapNode, self).__init__() QtGui.QWidget.__init__(self, parent) self.scanner = scanner self.x = x self.y = y self.danger = 'normal' self.calcDanger(danger) self.grads = {} self.grad = QtGui.QImage(MapNode.dangertocolor[self.danger]) def paintEvent(self, e): painter = QtGui.QPainter() painter.begin(self) self.drawMapNode(painter) painter.end() def drawMapNode(self, painter): realmap = GuiInternalCommunication.realmap radiusm = self.scanner.range radiusp = radiusm*realmap.pixpermet factor = radiusp/200 # basis grootte gradiënten is 200 pixels. grad = MapNode.gradimage[self.danger] grad = grad.scaled(grad.size().width()*factor, grad.size().height()*factor) painter.drawImage(self.x-100*factor,self.y-100*factor, grad) painter.drawImage(self.x-10, self.y-10,MapNode.btimage) painter.drawText(self.x-15, self.y+20, str(self.scanner.sensorid) + '-' + str(self.scanner.name)) ###################################################################### class MapBranch: branchpens = {"normal": QtGui.QPen(QtCore.Qt.green, 3, QtCore.Qt.DashLine), "elevated": QtGui.QPen(QtGui.QColor(255, 51, 0), 3, QtCore.Qt.DashLine), #mandarine orange hex is 255-165-0 "danger": QtGui.QPen(QtCore.Qt.red, 3, QtCore.Qt.DashLine)} def __init__(self, branch, mapnode1, mapnode2, danger = 0): self.mapnode1 = mapnode1 self.mapnode2 = mapnode2 self.branch = branch self.danger = danger self.calcDanger(danger) def drawMapBranch(self, painter): painter.setPen(MapBranch.branchpens[self.danger]) painter.drawLine(self.mapnode1.x, self.mapnode1.y, self.mapnode2.x, self.mapnode2.y) 

EDIT - I forgot to add code that adds nodes. Therefore, after you need to create a node event, this method starts the creation of a node:

 def addNode(self, scanner): mutexnode.acquire() try: coord = self.realmap.convertLatLon2Pix((scanner.latitude, scanner.longitude)) self.mapNodes[scanner.sensorid] = MapNode(scanner, coord[0], coord[1], parent = self) self.mapNodes[scanner.sensorid].move(coord[0],coord[1]) #self.mapNodes[scanner.sensorid].show() finally: mutexnode.release() 
+7
source share
1 answer

I would recommend that you use the QGraphicsScene and QGraphicsItem classes for your map instead of the usual QWidget classes, since they are made specifically to display a large number of graphic elements:

From the documentation:

The QGraphicsScene class provides a surface for managing a large number of 2D graphics.

The class serves as a container for QGraphicsItems. It is used in conjunction with QGraphicsView to render graphic elements, such as lines, rectangles, text, or even custom elements, on a 2D surface. QGraphicsScene is part of the Graphics View Framework.

QGraphicsScene also provides functionality that allows you to effectively determine both the location of elements and determine which elements are visible in an arbitrary area on the scene. Using the QGraphicsView widget, you can either visualize the entire scene or zoom in and view only parts of the scene.

You can also embed widgets received from QWidget in the scene, which should allow you to display almost any information. As a bonus, you get layering, quick transformations and ready-to-use mouse manipulation, which should be very useful for implementing an interactive map.

+3
source

All Articles