如何在 PyQT 中绘制节点和边?

发布于 2024-08-19 15:14:25 字数 72 浏览 1 评论 0原文

在 PyQT 中,如何在给定点绘制小“节点”并将它们与边缘连接?我找到的所有 PyQT 教程都是“绘制一个按钮!绘制一个复选框!”

In PyQT, how can I plot small "Nodes" at given points and connect them with edges? All of the PyQT tutorials I find are "plot a button! plot a checkbox!"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你是暖光i 2024-08-26 15:14:25

对此找到一个好的解释是一件很痛苦的事情(截至 2014 年底已经),并且由于这个问题准确地询问了我正在寻找的内容,因此我将发布我的内容的转录(从 C++ 到 Python)可以在这篇文章中找到。

代码如下,其基本原理如下:

  1. QGrahpicsItemQPainterPathQPainterPath.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_()

It has been a pain to find a good explanation for this (as of by the end of 2014 already), and since this question asks exactely what I was looking for, I'll post a transcription (from C++ to Python) of what I found in this post.

The code is below, and here is the rationale:

  1. QGrahpicsItem, QPainterPath and QPainterPath.Element are the classes you are looking for. Specifically, QPainterPath implements the kind of vector functionality you expect in applications such as CorelDraw, Adobe Illustrator, or Inkscape.
  2. The example below benefits from the pre-existing QGraphicsEllipseItem (for rendering nodes) and QGraphicsPathItem (for rendering the path itself), which inherit from QGraphicsItem.
  3. The Path constructor iterates over the QPainterPath elements, creating Node items for each one; Each of them, in turn, send updates to the parent Path object, which updates its path property accordingly.
  4. I found much, much easier to study the C++ Qt4 Docs than the rather less structured PyQt docs found elsewhere. Once you get used to mentally translate between C++ and Python, the docs themselves are a powerful way to learn how to use each class.

#!/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_()
丶视觉 2024-08-26 15:14:25

如果您希望能够与图中显示的对象进行交互,最好使用 QGraphicsScene。它处理缩放和平移,并且可以包含其他可以处理自己的交互的 QGraphicsItem 对象。

它非常容易使用,但会涉及一些开销,特别是如果您计划制作数千个对象。

您可以在此处找到 PyQt 教程。这和 API 文档应该可以帮助您入门。

If you want to be able to interact with the objects displayed in the plot, you will be better off using a QGraphicsScene. It handles zooming and panning and can contain other QGraphicsItem objects that can handle their own interactions.

It's very easy to use, but there is a bit of overhead involved, especially if you plan to make thousands of objects.

You can find a PyQt tutorial here. This and the API docs should get you started.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文