简体   繁体   English

PyQt - 在小部件上显示小部件

[英]PyQt - displaying widget on top of widget

I'm making an application that shows a map of an area and I'm trying to draw nodes on top of it which can represent information. 我正在创建一个显示区域地图的应用程序,我正在尝试在其上绘制可以表示信息的节点。

I made it all work, but did so simply by making one custom widget which I showed and printing everything again and again everytime information changed. 我完成了所有工作,但只是通过制作一个我展示的自定义小部件并在每次信息更改时一次又一次地打印所有内容。 Also I couldn't 'connect' the nodes to 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 every class a custom widget! 这让我想改进我的GUI,现在我正在尝试让每个类都成为一个自定义小部件! But there's a problem, my MapNodes aren't showing up anymore. 但是有一个问题,我的MapNodes不再出现了。

I searched stackoverflow and found this helpful thread: How to set absolute position of the widgets in qt 我搜索了stackoverflow并找到了这个有用的线程: 如何在qt中设置小部件的绝对位置

So I have to give my mapnodes a parent, and parent = the widget that is being shown (?) 所以我必须给我的mapnodes一个父级,而parent =正在显示的小部件(?)

Anyway, here is my throw at it, pasting the relevant code here. 无论如何,这是我的投入,在此粘贴相关代码。 Hint at where stuff might go horrible wrong: all the 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 the code that adds the nodes. 编辑 - 我忘了添加添加节点的代码。 So after an event comes in the node needs to be created, this method fires creating the 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()

I would recommend you to use the QGraphicsScene and QGraphicsItem classes for your map instead of normal QWidget classes, since they are made exactly for the purpose of displaying a large number of graphical items: 我建议您为地图使用QGraphicsScene和QGraphicsItem类而不是普通的QWidget类,因为它们完全是为了显示大量图形项目而制作的:

From the documentation: 从文档:

The QGraphicsScene class provides a surface for managing a large number of 2D graphical items. QGraphicsScene类提供了用于管理大量2D图形项的表面。

The class serves as a container for QGraphicsItems. 该类充当QGraphicsItems的容器。 It is used together with QGraphicsView for visualizing graphical items, such as lines, rectangles, text, or even custom items, on a 2D surface. 它与QGraphicsView一起用于在2D表面上可视化图形项目,例如线条,矩形,文本甚至自定义项目。 QGraphicsScene is part of the Graphics View Framework. QGraphicsScene是Graphics View Framework的一部分。

QGraphicsScene also provides functionality that lets you efficiently determine both the location of items, and for determining what items are visible within an arbitrary area on the scene. QGraphicsScene还提供了一些功能,可以让您有效地确定项目的位置,以及确定哪些项目在场景中的任意区域内可见。 With the QGraphicsView widget, you can either visualize the whole scene, or zoom in and view only parts of the scene. 使用QGraphicsView小部件,您可以显示整个场景,也可以放大并仅查看场景的某些部分。

You can also embed widgets derived from QWidget in the scene, which should allow you to display practically any kind of information. 您还可以在场景中嵌入从QWidget派生的小部件,这样您就可以显示任何类型的信息。 As a bonus, you will get layering, fast transformations and ready-to-use handling of mouse interactions, which should be quite useful for realizing an interactive map. 作为奖励,您将获得分层,快速转换和即时使用的鼠标交互处理,这对于实现交互式地图非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM