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

PyQt5实现绘制矩形时动态裁剪半透明遮罩区域的问题

屏幕区域高亮工具代码修正

需求:实现全屏半透明灰色遮罩,拖动鼠标时从遮罩中裁剪出清晰矩形区域,同时显示红色边框标记该区域。原代码问题是拖动时遮罩消失,无法持续保留遮罩并裁剪新区域。

修正后的完整代码

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QBrush, QColor, QPainter, QPen
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QDesktopWidget

class MainWidget(QWidget):
    def __init__(self):
        super().__init__()
        
        self.setWindowTitle("区域高亮工具")
        self.setGeometry(100, 100, 200, 200)
        
        self.screenshotButton = QPushButton("开始", self)
        self.screenshotButton.move(50, 50)
        self.screenshotButton.clicked.connect(self.openTransparentWidget)
        
    def openTransparentWidget(self):
        self.close()
        self.transparentWidget = TransparentWidget()
        self.transparentWidget.show()


class TransparentWidget(QWidget):
    def __init__(self):
        super().__init__()
        
        desktop = QDesktopWidget()
        screen_rect = desktop.screenGeometry()
        self.setGeometry(screen_rect)
        
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        
        self.start_pos = None
        self.end_pos = None
        self.mouse_pressed = False

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mouse_pressed = True
            self.start_pos = event.pos()

    def mouseMoveEvent(self, event):
        if self.mouse_pressed:
            self.end_pos = event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mouse_pressed = False
        
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        # 绘制全屏半透明灰色遮罩
        mask_brush = QBrush(QColor(200, 200, 200, 128))
        painter.setBrush(mask_brush)
        painter.drawRect(self.rect())

        # 从遮罩中裁剪拖动的矩形区域,并绘制红色边框
        if self.start_pos and self.end_pos:
            x = min(self.start_pos.x(), self.end_pos.x())
            y = min(self.start_pos.y(), self.end_pos.y())
            width = abs(self.start_pos.x() - self.end_pos.x())
            height = abs(self.start_pos.y() - self.end_pos.y())
            crop_rect = Qt.QRect(x, y, width, height)

            # 清除遮罩区域,显示下方屏幕
            painter.setCompositionMode(QPainter.CompositionMode_Clear)
            painter.drawRect(crop_rect)

            # 恢复混合模式,绘制红色边框
            painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
            pen = QPen(QColor(255, 0, 0), 2)
            painter.setPen(pen)
            painter.drawRect(crop_rect)


app = QApplication(sys.argv)
mainWidget = MainWidget()
mainWidget.show()
sys.exit(app.exec_())

关键修改说明

  • 始终绘制遮罩:无论是否开始拖动,paintEvent都会先绘制全屏半透明遮罩,解决原代码中遮罩消失的问题。
  • 用混合模式裁剪区域:通过CompositionMode_Clear清除拖动的矩形区域,让下方屏幕清晰显示。
  • 独立绘制边框:清除区域后切换回SourceOver模式绘制红色边框,避免边框被同步清除。
  • 优化变量逻辑:将分散的坐标变量改为start_pos/end_pos,代码逻辑更清晰。

效果:启动后点击「开始」进入全屏遮罩,按住左键拖动鼠标,会实时从遮罩中裁剪出清晰的矩形区域,同时显示红色边框,匹配示例图的高亮效果。

内容的提问来源于stack exchange,提问作者David O'Donovan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:25:44