如何在PyQT的QLabel上交互式绘制点到Pixmap上
我正在制作一个小的图形用户界面(GUI),里面有一个 QLabel,它可以从一个文件夹里加载图片并显示出来。我希望用户能够在这个图片上点击,点击的地方能出现一个小绿“x”。我尝试过重新实现 paintEvent 方法,但这并不是我想要的功能。paintEvent 是每次需要在 QLabel 上绘图时被调用的,而我希望保留底下的图片不变,只是在已经绘制的图片上添加点。最终,我希望用户能够在一系列图片中跟踪这些点,使用一些第三方的跟踪算法。因此,我需要用户能够移动点、删除点、添加点和修改点,而不需要重新绘制它们后面的图片。网上有很多关于简单绘制点的教程,但它们都涉及到重新实现 paintEvent 方法,然后把鼠标事件连接到 paintEvent。我想特别避免这样做。有没有什么建议?
1 个回答
其实你确实需要使用一个 paintEvent()
的重写。即使你只是想在一张图片上画东西,那个小部件还是需要能够重新绘制图片的部分,特别是当你移除或移动那些画在上面的东西时,这个过程就是在 paintEvent()
中完成的。如果你想在渲染中添加东西,也是在这里进行。
可以把 paintEvent()
想象成一个“绘制可见部分的事件”。如果你使用的是 QLabel
的子类,那么你的重写应该先调用 QLabel::paintEvent(e)
,然后再绘制你自己的内容。
听起来你会维护一个点的列表,所以在你的 paintEvent()
中应该按照你需要的方式绘制所有的点。
你的鼠标事件应该对你的点列表做一些操作(比如添加一个点或移动一个点),然后调用 update()
,这会触发对 paintEvent()
的调用,从而重新绘制整个小部件,包括背景图片和你更新后的点。不要把鼠标事件和 paintEvent()
连接在一起,也不要试图在 paintEvent()
中处理鼠标事件。
最重要的是要记住,鼠标事件会修改你的“模型”,而 paintEvent()
会在模型变化时绘制整个模型。即使有一种抽象的功能只要求你绘制新的东西或变化的东西,但在底层,很多东西仍然需要被擦除和重新绘制。
通过利用传入 paintEvent()
的事件对象中的区域信息,可以对这个过程进行优化,但通常情况下这并不是必要的。
你可以查看一个类似的例子,链接在这里:另一个问题的回答,虽然它可能和你已经看到的其他例子没有太大区别。不幸的是,这个例子不是用 Python 写的。
你也可以把所有的绘制工作做在一个内存中的图片上,然后只更新标签显示的图片,但重写 paintEvent()
是更好的选择。