You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt QGraphicsScene中实现鼠标拖动时实时显示绘制内容的方法

解决PyQt QGraphicsView实时绘制线条的问题

你的代码当前仅在鼠标左键释放时才向场景添加线条,所以拖动过程中看不到实时预览。要实现类似绘图软件的实时绘制效果,需要添加一个临时线条用于拖动时的动态更新,具体修改如下:

修改后的完整代码

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGraphicsView, QGraphicsScene, QApplication
from PyQt5.QtGui import QBrush, QColor, QPen, QPointF
from PyQt5.QtCore import Qt

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(400, 100, 1000, 800)
        self.setWindowTitle('Painter')
        self.background_color = '#242423'
        layout = QVBoxLayout(self)
        # 创建视图
        view = View()
        scene = QGraphicsScene()
        scene.setBackgroundBrush(QBrush(QColor(self.background_color)))
        scene.setSceneRect(0, 0, 1000, 800)  # 扩大场景范围,避免绘制区域受限

        layout.addWidget(view)
        view.setScene(scene)
          
class View(QGraphicsView):
    def __init__(self):
        super().__init__()
        self.pen = QPen()
        self.pen.setColor(Qt.red)
        self.start = QPointF()
        self.end = QPointF()
        self.temp_line = None  # 用于实时预览的临时线条
        self.setMouseTracking(True)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.start = self.mapToScene(event.pos())
            # 初始化临时线条,初始时起点和终点重合
            self.temp_line = self.scene().addLine(self.start.x(), self.start.y(), self.start.x(), self.start.y(), self.pen)
       
    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton and self.temp_line is not None:
            self.end = self.mapToScene(event.pos())
            # 更新临时线条的端点,实现实时预览
            self.temp_line.setLine(self.start.x(), self.start.y(), self.end.x(), self.end.y())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.temp_line is not None:
            self.end = self.mapToScene(event.pos())
            # 处理点击但未拖动的情况
            if self.start.x() == self.end.x() and self.start.y() == self.end.y():
                self.scene().removeItem(self.temp_line)
            else:
                # 根据原逻辑判断绘制水平线或垂直线
                if abs(self.end.y() - self.start.y()) < 20:
                    # 替换临时线条为水平线
                    self.scene().removeItem(self.temp_line)
                    self.scene().addLine(self.start.x(), self.start.y(), self.end.x(), self.start.y(), self.pen)
                elif abs(self.end.x() - self.start.x()) < 20:
                    # 替换临时线条为垂直线
                    self.scene().removeItem(self.temp_line)
                    self.scene().addLine(self.start.x(), self.start.y(), self.start.x(), self.end.y(), self.pen)
                else:
                    # 这里可以添加绘制矩形的逻辑,原代码未实现,暂时保留临时线条
                    pass
            self.temp_line = None  # 重置临时线条对象

if __name__ == '__main__':
    app = QApplication([])
    window = Window()
    window.show()
    app.exec()

关键改动说明

  • 添加临时线条对象:在View类中新增self.temp_line变量,用于存储拖动过程中的预览线条。
  • 鼠标按下时初始化临时线条:在mousePressEvent中创建初始的临时线条,起点和终点重合。
  • 鼠标移动时更新临时线条:在mouseMoveEvent中实时修改临时线条的端点坐标,实现拖动时的实时预览。
  • 鼠标释放时确认绘制:释放鼠标后,根据原逻辑判断是保留水平线/垂直线,还是移除无效的点击(未拖动的情况),最后重置临时线条对象。
  • 移除全局变量scene:改用self.scene()获取当前视图绑定的场景,避免全局变量带来的耦合问题。
  • 扩大场景范围:将scene.setSceneRect的尺寸调整为与窗口匹配,避免绘制时线条超出场景范围无法显示。

内容的提问来源于stack exchange,提问作者Abdallah Eldesouky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:57:29