如何在PyQT中的QLabel上交互式地绘制点到一个Pixmap上?

3
我正在构建一个小型GUI界面,我有一个QLabel,通过将图像设置为pixmap,从目录中绘制图像。我希望用户能够交互式地点击此pixmap上的点,并在所点击的位置上出现一个小绿色“x”。我尝试重新实现paintEvent方法,但这完全不是我想要的功能。paintEvent是每次需要在QLabel上绘制时调用的方法...而我想保留基本绘图(即图像),只需在已绘制的图像上方放置点即可。最终,我希望用户能够通过第三方跟踪算法交互地跟踪这些点穿过一系列图像。因此,我需要具备让用户移动点、删除点、添加点和修改点的能力,而无需重新绘制它们后面的图像。有几个在线教程可以简单地绘制点,但它们都涉及重新实现paintEvent方法,然后将mouseEvent连接到paintEvent。我正试图避免这种情况。有什么建议吗?
1个回答

3
实际上,您确实需要使用paintEvent()覆盖。即使您只想在图像上绘制东西,如果您移除或移动覆盖在其上的东西,则小部件仍然需要能够重新绘制图像的部分,而这发生在paintEvent()中。如果要添加渲染内容,那就必须在此处添加。
paintEvent()视为“绘制可见部分的整个部分事件”。如果您正在使用QLabel的子类,则覆盖应调用QLabel::paintEvent(e),然后再添加自己的内容。
听起来您将维护点列表,因此您的paintEvent()部分应以所需方式绘制所有点。
您的鼠标事件应对点列表执行某些操作(例如添加点或移动点),然后调用update(),这将触发对paintEvent()的调用,从而使用背景图像和更新的点重绘整个小部件。不应将鼠标事件连接到paintEvent(),也不应尝试在其中跟踪或处理鼠标事件。
最重要的是,鼠标事件将修改您的“模型”,并且每当模型更改时,paintEvent()都会绘制整个模型。即使有一种只需要您绘制新内容或更改的抽象/函数,在内部仍需要擦除和重绘许多内容。
可以通过利用传递给paintEvent()的事件对象中的区域信息来进行优化,但这通常是不必要的。
您可以在内存中完成所有渲染工作,然后仅更新标签显示的图像,但覆盖paintEvent()是更好的选择。您可以查看我提供的另一个问题的答案中的相似示例,尽管它可能与您已经看到的其他示例没有太大的区别。不幸的是,它不是用Python编写的。

因为我是新手,有几个问题想问一下:(1)当你说“调用更新”时,那是像在mousePressEvent(self,event)里面一样的鼠标事件吗?我可以调用event.update(或者是self.update)吗?(2)目前我正在发射我的自定义信号,SIGNAL("leftclick"),并将(x,y)鼠标位置作为传递的参数。我该如何让paintEvent响应这个自定义信号呢,或者这并不必要。 - ely
在您的点击信号槽中,我假设这将是您的QLable子类中的一个槽,您将根据x、y信息对点列表进行某种更改(应存储在成员变量中),然后只需调用update()。就像那样。然后,在您的paintEvent()重写内部,您将使用点的成员变量来决定绘制事物的位置。调用update()触发小部件重新绘制自身,其中包括对paintEvent()的调用。 - Arnold Spence
明白了。所以我需要用户交互来改变图形持有对象的私有属性,这里是一个QLabel,然后在更新绘图时让paintEvent访问这些属性。 - ely
这就是要点,没错 :) - Arnold Spence
再次感谢您的帮助。如果您有更多时间思考这个问题,我在这里添加了一个后续问题:http://stackoverflow.com/questions/6222044/python-pyqt-how-to-detect-mouse-events-when-clicking-text-points-in-a-pixmap - ely

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