Как я могу нарисовать узлы и ребра в PyQT?

В PyQT, как я могу построить маленькие "Узлы" в заданных точках и соединить их с ребрами? Все учебники по PyQT, которые я нахожу, - "Нарисуй кнопку! Нарисуй флажок!"

Огромное спасибо заранее

2 ответа

Было трудно найти хорошее объяснение этому (уже к концу 2014 года), и, поскольку этот вопрос точно задает то, что я искал, я опубликую транскрипцию (от C++ до Python) того, что я нашел в этом посте.

Код ниже, и вот обоснование:

  1. QGrahpicsItem, QPainterPath а также QPainterPath.Element те классы, которые вы ищете. В частности, QPainterPath реализует ту векторную функциональность, которую вы ожидаете в таких приложениях, как CorelDraw, Adobe Illustrator или Inkscape.
  2. Пример ниже извлекает выгоду из ранее существовавшего QGraphicsEllipseItem (для рендеринга узлов) и QGraphicsPathItem (для рендеринга самого пути), который наследуется от QGraphicsItem,
  3. Path Конструктор перебирает QPainterPath элементы, создающие Node предметы для каждого; Каждый из них, в свою очередь, отправляет обновления родительскому объекту Path, который обновляет его path собственность соответственно.
  4. Я обнаружил, что намного легче изучать документы C++ Qt4, чем менее структурированные документы PyQt, найденные где-либо еще. Как только вы привыкнете мысленно переводить между C++ и Python, сами документы станут мощным способом научиться использовать каждый класс.

#!/usr/bin/env python
# coding: utf-8

from PyQt4.QtGui import *
from PyQt4.QtCore import *

rad = 5

class Node(QGraphicsEllipseItem):
    def __init__(self, path, index):
        super(Node, self).__init__(-rad, -rad, 2*rad, 2*rad)

        self.rad = rad
        self.path = path
        self.index = index

        self.setZValue(1)
        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self.setBrush(Qt.green)

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionChange:
            self.path.updateElement(self.index, value.toPointF())
        return QGraphicsEllipseItem.itemChange(self, change, value)


class Path(QGraphicsPathItem):
    def __init__(self, path, scene):
        super(Path, self).__init__(path)
        for i in xrange(path.elementCount()):
            node = Node(self, i)
            node.setPos(QPointF(path.elementAt(i)))
            scene.addItem(node)
        self.setPen(QPen(Qt.red, 1.75))        

    def updateElement(self, index, pos):
        path.setElementPositionAt(index, pos.x(), pos.y())
        self.setPath(path)


if __name__ == "__main__":

    app = QApplication([])

    path = QPainterPath()
    path.moveTo(0,0)
    path.cubicTo(-30, 70, 35, 115, 100, 100);
    path.lineTo(200, 100);
    path.cubicTo(200, 30, 150, -35, 60, -30);

    scene = QGraphicsScene()
    scene.addItem(Path(path, scene))

    view = QGraphicsView(scene)
    view.setRenderHint(QPainter.Antialiasing)
    view.resize(600, 400)
    view.show()
    app.exec_()

Если вы хотите иметь возможность взаимодействовать с объектами, отображаемыми на графике, вам лучше использовать QGraphicsScene. Он обрабатывает масштабирование и панорамирование и может содержать другие объекты QGraphicsItem, которые могут обрабатывать их собственные взаимодействия.

Он очень прост в использовании, но в нем есть некоторые накладные расходы, особенно если вы планируете создавать тысячи объектов.

Вы можете найти учебник по PyQt здесь. Это и документация по API должны помочь вам начать.

Другие вопросы по тегам