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

10
在PyQT中,我如何在给定的点上绘制小的“节点”并用边连接它们? 我找到的所有PyQT教程都是“绘制按钮!绘制复选框!”
2个回答

4

我曾经很痛苦地寻找一个好的解释(截至2014年底),由于这个问题正是我在寻找的,所以我将发布一个转录(从C++到Python)我在this post中发现的内容。

下面是代码,这里是原理:

  1. QGrahpicsItemQPainterPathQPainterPath.Element是你需要寻找的类。特别地,QPainterPath实现了在像CorelDraw、Adobe Illustrator或Inkscape这样的应用程序中所期望的矢量功能。
  2. 下面的示例受益于已有的QGraphicsEllipseItem(用于渲染节点)和QGraphicsPathItem(用于渲染路径本身),它们都继承自QGraphicsItem
  3. Path构造函数遍历QPainterPath元素,为每个元素创建一个Node项;每个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_()

这个代码最近帮了我很多忙!谢谢!另外,我正在尝试在Node类中绘制一个函数 - mousePressEvent / 中键单击以将控制点添加到路径lineTo()中。这样,从A点>B点,我可以在中间添加C点。所以我可以做一个“L”形...意味着> A/B左上/右下和C是角落...但我不确定是否正确,因为当我按下时我没有检测到红色绘制线,只有圆圈...有什么提示可以让我如何做到这一点吗?谢谢! - Dariusz
1
@Dariusz 我相信在Qt中有一些内置的“mouseover”事件或标志,但我不记得它的名称,也不知道哪个类拥有它。我会从QGraphicsItem开始搜索。 - heltonbiker
1
@Dariusz,实际上我找到它们了,它们是hoverEnterEventhoverLeaveEvent,在这里找到。 - heltonbiker

3
如果您想与绘图中显示的对象进行交互,最好使用QGraphicsScene。它处理缩放和平移,并可以包含其他QGraphicsItem对象,这些对象可以处理自己的交互。
它非常易于使用,但涉及一些开销,特别是如果您计划创建数千个对象。
您可以在这里找到一个PyQt教程。这个教程和API文档应该能让您入门。

不太清楚你提供的教程。每当我关闭PyQt应用程序时,就会出现分段错误。 - rbaleksandar
这个教程是从2008年开始的,所以有些东西可能已经发生了变化。Segfault-on-close通常意味着您的基本QT类(QApplication、QMainWindow等)的生命周期/配置存在问题。如果您可以运行适用于您PyQt版本的教程,那么您应该能够整合必要的项目来使QGraphicsScene正常工作。 - drxzcl
我已经解决了我的问题。但是,版本比较旧。 - rbaleksandar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接