如何在PyQT的QLabel上交互式绘制点到Pixmap上

3 投票
1 回答
3058 浏览
提问于 2025-04-16 18:52

我正在制作一个小的图形用户界面(GUI),里面有一个 QLabel,它可以从一个文件夹里加载图片并显示出来。我希望用户能够在这个图片上点击,点击的地方能出现一个小绿“x”。我尝试过重新实现 paintEvent 方法,但这并不是我想要的功能。paintEvent 是每次需要在 QLabel 上绘图时被调用的,而我希望保留底下的图片不变,只是在已经绘制的图片上添加点。最终,我希望用户能够在一系列图片中跟踪这些点,使用一些第三方的跟踪算法。因此,我需要用户能够移动点、删除点、添加点和修改点,而不需要重新绘制它们后面的图片。网上有很多关于简单绘制点的教程,但它们都涉及到重新实现 paintEvent 方法,然后把鼠标事件连接到 paintEvent。我想特别避免这样做。有没有什么建议?

1 个回答

3

其实你确实需要使用一个 paintEvent() 的重写。即使你只是想在一张图片上画东西,那个小部件还是需要能够重新绘制图片的部分,特别是当你移除或移动那些画在上面的东西时,这个过程就是在 paintEvent() 中完成的。如果你想在渲染中添加东西,也是在这里进行。

可以把 paintEvent() 想象成一个“绘制可见部分的事件”。如果你使用的是 QLabel 的子类,那么你的重写应该先调用 QLabel::paintEvent(e),然后再绘制你自己的内容。

听起来你会维护一个点的列表,所以在你的 paintEvent() 中应该按照你需要的方式绘制所有的点。

你的鼠标事件应该对你的点列表做一些操作(比如添加一个点或移动一个点),然后调用 update(),这会触发对 paintEvent() 的调用,从而重新绘制整个小部件,包括背景图片和你更新后的点。不要把鼠标事件和 paintEvent() 连接在一起,也不要试图在 paintEvent() 中处理鼠标事件。

最重要的是要记住,鼠标事件会修改你的“模型”,而 paintEvent() 会在模型变化时绘制整个模型。即使有一种抽象的功能只要求你绘制新的东西或变化的东西,但在底层,很多东西仍然需要被擦除和重新绘制。

通过利用传入 paintEvent() 的事件对象中的区域信息,可以对这个过程进行优化,但通常情况下这并不是必要的。

你可以查看一个类似的例子,链接在这里:另一个问题的回答,虽然它可能和你已经看到的其他例子没有太大区别。不幸的是,这个例子不是用 Python 写的。

你也可以把所有的绘制工作做在一个内存中的图片上,然后只更新标签显示的图片,但重写 paintEvent() 是更好的选择。

撰写回答