def mre(self, event): # функция отпускания мыши im_width, im_height = int(self.im.size[0]), int( self.im.size[1]) # ширина и высота изображения gv_width = list(QRect.getRect(self.ui.graphicsView.geometry()))[ 2] # ширина обозревателя graphicsView gv_height = list(QRect.getRect(self.ui.graphicsView.geometry()))[ 3] # высота обозревателя graphicsView self.rect = self.rubberBand.geometry() self.coords = list(QRect.getCoords( self.rect)) # координаты выделенного прямоугольника self.coords[2] = self.borders(self.coords[2], gv_width) self.coords[3] = self.borders(self.coords[3], gv_height) c = self.coords self.rubberBand.hide() # скрыть прямоугольник self.ui.label_7.setText("select coords: {} ".format(str(self.coords))) scr_v = int(self.ui.graphicsView.verticalScrollBar().sliderPosition() ) # позиция вертикального скрола scr_h = int(self.ui.graphicsView.horizontalScrollBar().sliderPosition( )) # позиция горизонтального скрола self.real_coords = [ c[0] + scr_h, c[1] + scr_v, c[2] + scr_h, c[3] + scr_v ] # реальные координаты self.real_coords[2] = self.borders(self.real_coords[2], im_width) self.real_coords[3] = self.borders(self.real_coords[3], im_height) self.ui.label_8.setText("real coords: {} ".format(str( self.real_coords)))
def selected(self, rect: QRect): x = rect.getRect()[0] y = rect.getRect()[1] width = rect.getRect()[2] height = rect.getRect()[3] img = self.reference_img[y:y + height, x:x + width, :] self.workflow[self.row] = (self.workflow[self.row][0], img) self.build_content()
def qrect_to_json(val: QRect): return json.dumps(val.getRect())
class LabelCanvas(QWidget): def __init__(self, statusbar=None, labelCoordinates=None, labelQLabel=None, labelEdit=None): super(LabelCanvas, self).__init__() self.statusbar = statusbar self.labelCoordinates = labelCoordinates self.labelEdit = labelEdit self.labelQLabel = labelQLabel if self.labelQLabel: self.labelQLabel.hide() if self.labelEdit: self.labelEdit.hide() self.labelEdit.returnPressed.connect(self.labelEditEnterPress) self.setMouseTracking(True) self.setFocusPolicy(Qt.WheelFocus) self.painter = QPainter() self.scaleRate = 0.2 self.pixmap = QPixmap('icon/sample.jpg') self.pmapRect = self.pixmap.rect() self.pmapShowAreaRect = self.pixmap.rect() self.drag = False self.labels = () self.mousex = 0 self.mousey = 0 self.labels = [] self.templabel = [] self.labeling = False self.labelsRect = [] self.deleteRects = [] self.textRects = [] def loadPixmap(self, pixmap, labels=None): self.pixmap = pixmap self.pmapRect = pixmap.rect() self.pmapShowAreaRect = pixmap.rect() self.labels.clear() if labels: self.labels.extend(labels) self.repaint() def paintEvent(self, e): self.painter.begin(self) # 绘制图片内容 self.painter.drawPixmap(self.rect(), self.pixmap, self.pmapShowAreaRect) # 绘制图片区域预览 self.painter.setPen(QColor(0, 0, 0)) scale = min(self.width() / self.pixmap.width() / 5, self.height() / self.pixmap.height() / 5) self.pmapPreRect = QRect(0, 0, self.pixmap.width() * scale, self.pixmap.height() * scale) margin = int(min(self.width(), self.height()) / 16) self.pmapPreRect.moveTopRight(QPoint(self.width() - margin, margin)) self.painter.drawRect(self.pmapPreRect) # 绘制图片展示区域预览 self.painter.setPen(QColor(255, 0, 0)) pmapprerect = self.pmapPreRect.getRect() pmapshowarearect = self.pmapShowAreaRect.getRect() x = pmapprerect[0] + self.pmapPreRect.width( ) * pmapshowarearect[0] / self.pixmap.width() y = pmapprerect[1] + self.pmapPreRect.height( ) * pmapshowarearect[1] / self.pixmap.height() w = scale * self.pmapShowAreaRect.width() h = scale * self.pmapShowAreaRect.height() self.pmapShowAreaPreRect = QRect(x, y, w, h) self.painter.drawRect(self.pmapShowAreaPreRect) self.dragAreaRect = QRect( self.pmapPreRect.x() - self.pmapShowAreaPreRect.width(), self.pmapPreRect.y() - self.pmapShowAreaPreRect.height(), self.pmapShowAreaPreRect.width() + self.pmapPreRect.width(), self.pmapShowAreaPreRect.height() + self.pmapPreRect.height()) # 绘制缩放中心点标线 self.painter.setPen(QColor(255, 0, 0)) self.painter.drawLine(self.width() / 3, self.height() / 2, self.width() / 3 * 2, self.height() / 2) self.painter.drawLine(self.width() / 2, self.height() / 3, self.width() / 2, self.height() / 3 * 2) # 绘制鼠标位置标线 if self.labeling: self.painter.setPen(QColor(0, 0, 0)) self.painter.drawLine(self.mousex, 0, self.mousex, self.height()) self.painter.drawLine(0, self.mousey, self.width(), self.mousey) # 绘制正在编辑中的label位置 if self.templabel: for i in range(int(len(self.templabel) / 2)): imagex, imagey = self.templabel[0 + 2 * i], self.templabel[1 + 2 * i] if self.pmapShowAreaRect.contains(imagex, imagey): widgetx, widgety = self.imageXY2WidgetXY(imagex, imagey) self.painter.setPen(QPen(Qt.red, 5)) self.painter.drawPoint(widgetx, widgety) pen = QPen(Qt.black, 2, Qt.SolidLine) pen.setStyle(Qt.DashDotDotLine) self.painter.setPen(pen) self.painter.drawLine(widgetx, 0, widgetx, self.height()) self.painter.drawLine(0, widgety, self.width(), widgety) # 绘制已标记内容 self.deleteRects.clear() self.textRects.clear() self.painter.setPen(QColor(168, 34, 3)) self.painter.setFont(QFont('Decorative', 12)) metrics = self.painter.fontMetrics() deleteRectWidth, deleteRectHeight = metrics.height( ) * 1.2, metrics.height() * 1.2 separatorheight = margin / 10 pmapprerect = self.pmapPreRect.getRect() topRightx, topRighty = self.width( ) - margin, pmapprerect[1] + pmapprerect[3] + margin / 4 for i in range(len(self.labels)): label = self.labels[i] # 绘制文字展示信息 text = label[4] deleteRect = QRect( topRightx - deleteRectWidth, topRighty + (deleteRectHeight + separatorheight) * i, deleteRectWidth, deleteRectHeight) self.painter.drawRect(deleteRect) self.painter.drawLine(deleteRect.topLeft(), deleteRect.bottomRight()) self.painter.drawLine(deleteRect.topRight(), deleteRect.bottomLeft()) self.deleteRects.append(deleteRect) deleterect = deleteRect.getRect() textWidth, textHeight = metrics.width(text), metrics.height() textRect = QRect(deleterect[0] - textWidth - metrics.height(), deleterect[1], textWidth + metrics.height(), deleterect[3]) self.painter.drawRect(textRect) self.painter.drawText(textRect, Qt.AlignCenter, text) self.textRects.append(textRect) # 在图片上绘制标签矩形框 labelPixmapX, labelPixmapY, labelPixmapWidth, labelPixmapHeight = label[: 4] labelPixmapRect = QRect(labelPixmapX, labelPixmapY, labelPixmapWidth, labelPixmapHeight) intersectedRect = self.pmapShowAreaRect.intersected( labelPixmapRect) if intersectedRect: pixmapTopLeftPoint, pixmapBottomRightPoint = intersectedRect.topLeft( ), intersectedRect.bottomRight() widgetTopLeftPointX, widgetTopLeftPointY = self.imageXY2WidgetXY( pixmapTopLeftPoint.x(), pixmapTopLeftPoint.y()) widgetTopLeftPoint = QPoint(widgetTopLeftPointX, widgetTopLeftPointY) widgetBottomRightPointX, widgetBottomRightPointY = self.imageXY2WidgetXY( pixmapBottomRightPoint.x(), pixmapBottomRightPoint.y()) widgetBottomRightPoint = QPoint(widgetBottomRightPointX, widgetBottomRightPointY) labelRect = QRect(widgetTopLeftPoint, widgetBottomRightPoint) self.painter.drawRect(labelRect) # 绘制标签名 labelrect = labelRect.getRect() textRect1 = QRect(labelrect[0], labelrect[1] - textHeight, textWidth, textHeight) # self.painter.drawRect(textRect1) self.painter.drawText(textRect1, Qt.AlignCenter, text) self.painter.end() # 将图片中像素坐标转化为控件坐标 def imageXY2WidgetXY(self, imagex, imagey): pmapshowarearect = self.pmapShowAreaRect.getRect() widgetx = (imagex - pmapshowarearect[0]) / pmapshowarearect[2] * self.width() widgety = (imagey - pmapshowarearect[1]) / pmapshowarearect[3] * self.height() return widgetx, widgety # 恢复图片初加载状态 def restart(self): self.pmapRect = self.pixmap.rect() self.pmapShowAreaRect = self.pixmap.rect() self.repaint() # 初始化一个新的标签 def label(self): self.templabel.clear() self.labeling = True if self.labelQLabel: self.labelQLabel.setText('') self.labelQLabel.show() self.status('开始创建标签', delay=500) self.repaint() # 移除最后一次添加的像素点 def undo(self): self.removeTempPoint() # 返回标签内容 def save(self): self.clearStatus() return self.labels def clearStatus(self): if self.labelQLabel: self.labelQLabel.hide() if self.labelEdit: self.labelEdit.hide() if self.templabel: self.templabel.clear() self.labeling = False self.repaint() # 添加标记点 def addTempPoint(self, x, y): if self.labelQLabel.isHidden(): self.labelQLabel.show() self.templabel.append(x) self.templabel.append(y) self.statusLabel('创建标签->' + str(self.templabel)) if len(self.templabel) == 4: self.statusLabel('标签内容为->' + str(self.templabel) + ' 请输入标签名->') self.labeling = False self.labelEdit.setText('') self.labelEdit.setFocus() self.labelEdit.show() self.repaint() # 移除标记点 def removeTempPoint(self): if self.templabel: self.templabel = self.templabel[:-2] self.repaint() self.labelEdit.setText('') self.labelEdit.hide() self.labelQLabel.setText('标签内容->' + str(self.templabel)) if len(self.templabel) == 0: self.labelQLabel.hide() # 监听滚轮事件 def wheelEvent(self, event): if event.angleDelta: if event.angleDelta().y() / 120 >= 1: self.enlargeByCenter() else: self.narrowByCenter() # 监听鼠标双击事件 def mouseDoubleClickEvent(self, event): if self.labeling: if len(self.templabel) >= 4: self.label() self.status('标记错误,已重置', delay=800) return pointx = math.ceil(self.pmapShowAreaRect.getRect()[0] + (self.pmapShowAreaRect.width() * event.pos().x() / self.width())) pointy = math.ceil(self.pmapShowAreaRect.getRect()[1] + (self.pmapShowAreaRect.height() * event.pos().y() / self.height())) if self.pmapRect.contains(pointx, pointy): self.addTempPoint(pointx, pointy) else: self.status('请选择图片区域', delay=500) # 监听键盘ESC键按下 def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: if self.labelQLabel: self.labelQLabel.hide() if self.labelEdit: self.labelEdit.hide() if self.templabel: self.templabel.clear() self.labeling = False self.repaint() def labelEditEnterPress(self): self.labelEdit.hide() if self.labelQLabel: self.labelQLabel.hide() labelText = self.labelEdit.text() templabelrect = [ min(self.templabel[0], self.templabel[2]), min(self.templabel[1], self.templabel[3]), abs(self.templabel[0] - self.templabel[2]), abs(self.templabel[1] - self.templabel[3]), '默认标签名' if labelText.strip() == '' else labelText.strip() ] self.status('标签创建成功->' + str(templabelrect), delay=1000) self.labels.append(templabelrect) self.templabel.clear() self.labeling = False self.repaint() # 监听鼠标按下事件 def mousePressEvent(self, event): if self.pmapShowAreaPreRect.contains(event.pos().x(), event.pos().y()): self.drag = True elif self.pmapPreRect.contains(event.pos().x(), event.pos().y()): pmapprerect = self.pmapPreRect.getRect() pmaprect = self.pmapRect.getRect() scale = pmaprect[2] / pmapprerect[2] ximage = (event.pos().x() - pmapprerect[0]) * scale yimage = (event.pos().y() - pmapprerect[1]) * scale self.pmapShowAreaRect.moveCenter(QPoint(ximage, yimage)) self.repaint() else: self.labelTextClickCheck(event.pos().x(), event.pos().y()) # 鼠标点击到标签逻辑 def labelTextClickCheck(self, widgetx, widgety): for i in range(len(self.textRects)): if self.textRects[i].contains(widgetx, widgety): self.status(str(self.labels[i]), delay=1000) labelx, labely, labelwidth, labelheight = self.labels[i][:4] self.pmapShowAreaRect.moveCenter( QRect(labelx, labely, labelwidth, labelheight).center()) self.repaint() return for i in range(len(self.deleteRects)): if self.deleteRects[i].contains(widgetx, widgety): self.labels.pop(i) self.repaint() return # 鼠标移动事件 def mouseMoveEvent(self, event): pointx = math.ceil(self.pmapShowAreaRect.getRect()[0] + (self.pmapShowAreaRect.width() * event.pos().x() / self.width())) pointy = math.ceil(self.pmapShowAreaRect.getRect()[1] + (self.pmapShowAreaRect.height() * event.pos().y() / self.height())) self.labelCoordinates.setText('X: %s Y: %s' % (pointx, pointy)) if self.drag and self.dragAreaRect.contains(event.pos().x(), event.pos().y()): pmapprerect = self.pmapPreRect.getRect() pmaprect = self.pmapRect.getRect() scale = pmaprect[2] / pmapprerect[2] ximage = (event.pos().x() - pmapprerect[0]) * scale yimage = (event.pos().y() - pmapprerect[1]) * scale self.pmapShowAreaRect.moveCenter(QPoint(ximage, yimage)) self.repaint() else: if self.pmapPreRect.contains(event.pos().x(), event.pos().y()): self.mousex, self.mousey = 0, 0 self.repaint() else: self.mousex, self.mousey = event.pos().x(), event.pos().y() self.repaint() def mouseReleaseEvent(self, event): self.drag = False # 以图片中心放大图片 def enlargeByCenter(self): pmapshowarearect = self.pmapShowAreaRect.getRect() pmaprect = self.pmapRect.getRect() if pmapshowarearect[2] <= pmaprect[2] / 20 or pmapshowarearect[ 3] <= pmaprect[3] / 20: return self.pmapShowAreaRect.adjust( self.pmapShowAreaRect.width() * self.scaleRate, self.pmapShowAreaRect.height() * self.scaleRate, -self.pmapShowAreaRect.width() * self.scaleRate, -self.pmapShowAreaRect.height() * self.scaleRate) self.repaint() # 以图片中心缩放图片 def narrowByCenter(self): pmapshowarearect = self.pmapShowAreaRect.getRect() pmaprect = self.pmapRect.getRect() if pmapshowarearect[2] >= pmaprect[2] or pmapshowarearect[ 3] >= pmaprect[3]: return self.pmapShowAreaRect.adjust( -self.pmapShowAreaRect.width() * self.scaleRate / (1 - 2 * self.scaleRate), -self.pmapShowAreaRect.height() * self.scaleRate / (1 - 2 * self.scaleRate), self.pmapShowAreaRect.width() * self.scaleRate / (1 - 2 * self.scaleRate), self.pmapShowAreaRect.height() * self.scaleRate / (1 - 2 * self.scaleRate)) self.repaint() def statusLabel(self, message): if self.labelQLabel: self.labelQLabel.setText(message) def status(self, message, delay=-1): if self.statusbar: self.statusbar.showMessage(message, delay) def labelCoord(self, message): if self.labelCoordinates: self.labelCoordinates.setText(message) def setStatusBar(self, statusbar): self.statusbar = statusbar def setlabelCoordinates(self, labelCoordinates): self.labelCoordinates = labelCoordinates
def paintEvent(self, e): self.painter.begin(self) # 绘制图片内容 self.painter.drawPixmap(self.rect(), self.pixmap, self.pmapShowAreaRect) # 绘制图片区域预览 self.painter.setPen(QColor(0, 0, 0)) scale = min(self.width() / self.pixmap.width() / 5, self.height() / self.pixmap.height() / 5) self.pmapPreRect = QRect(0, 0, self.pixmap.width() * scale, self.pixmap.height() * scale) margin = int(min(self.width(), self.height()) / 16) self.pmapPreRect.moveTopRight(QPoint(self.width() - margin, margin)) self.painter.drawRect(self.pmapPreRect) # 绘制图片展示区域预览 self.painter.setPen(QColor(255, 0, 0)) pmapprerect = self.pmapPreRect.getRect() pmapshowarearect = self.pmapShowAreaRect.getRect() x = pmapprerect[0] + self.pmapPreRect.width( ) * pmapshowarearect[0] / self.pixmap.width() y = pmapprerect[1] + self.pmapPreRect.height( ) * pmapshowarearect[1] / self.pixmap.height() w = scale * self.pmapShowAreaRect.width() h = scale * self.pmapShowAreaRect.height() self.pmapShowAreaPreRect = QRect(x, y, w, h) self.painter.drawRect(self.pmapShowAreaPreRect) self.dragAreaRect = QRect( self.pmapPreRect.x() - self.pmapShowAreaPreRect.width(), self.pmapPreRect.y() - self.pmapShowAreaPreRect.height(), self.pmapShowAreaPreRect.width() + self.pmapPreRect.width(), self.pmapShowAreaPreRect.height() + self.pmapPreRect.height()) # 绘制缩放中心点标线 self.painter.setPen(QColor(255, 0, 0)) self.painter.drawLine(self.width() / 3, self.height() / 2, self.width() / 3 * 2, self.height() / 2) self.painter.drawLine(self.width() / 2, self.height() / 3, self.width() / 2, self.height() / 3 * 2) # 绘制鼠标位置标线 if self.labeling: self.painter.setPen(QColor(0, 0, 0)) self.painter.drawLine(self.mousex, 0, self.mousex, self.height()) self.painter.drawLine(0, self.mousey, self.width(), self.mousey) # 绘制正在编辑中的label位置 if self.templabel: for i in range(int(len(self.templabel) / 2)): imagex, imagey = self.templabel[0 + 2 * i], self.templabel[1 + 2 * i] if self.pmapShowAreaRect.contains(imagex, imagey): widgetx, widgety = self.imageXY2WidgetXY(imagex, imagey) self.painter.setPen(QPen(Qt.red, 5)) self.painter.drawPoint(widgetx, widgety) pen = QPen(Qt.black, 2, Qt.SolidLine) pen.setStyle(Qt.DashDotDotLine) self.painter.setPen(pen) self.painter.drawLine(widgetx, 0, widgetx, self.height()) self.painter.drawLine(0, widgety, self.width(), widgety) # 绘制已标记内容 self.deleteRects.clear() self.textRects.clear() self.painter.setPen(QColor(168, 34, 3)) self.painter.setFont(QFont('Decorative', 12)) metrics = self.painter.fontMetrics() deleteRectWidth, deleteRectHeight = metrics.height( ) * 1.2, metrics.height() * 1.2 separatorheight = margin / 10 pmapprerect = self.pmapPreRect.getRect() topRightx, topRighty = self.width( ) - margin, pmapprerect[1] + pmapprerect[3] + margin / 4 for i in range(len(self.labels)): label = self.labels[i] # 绘制文字展示信息 text = label[4] deleteRect = QRect( topRightx - deleteRectWidth, topRighty + (deleteRectHeight + separatorheight) * i, deleteRectWidth, deleteRectHeight) self.painter.drawRect(deleteRect) self.painter.drawLine(deleteRect.topLeft(), deleteRect.bottomRight()) self.painter.drawLine(deleteRect.topRight(), deleteRect.bottomLeft()) self.deleteRects.append(deleteRect) deleterect = deleteRect.getRect() textWidth, textHeight = metrics.width(text), metrics.height() textRect = QRect(deleterect[0] - textWidth - metrics.height(), deleterect[1], textWidth + metrics.height(), deleterect[3]) self.painter.drawRect(textRect) self.painter.drawText(textRect, Qt.AlignCenter, text) self.textRects.append(textRect) # 在图片上绘制标签矩形框 labelPixmapX, labelPixmapY, labelPixmapWidth, labelPixmapHeight = label[: 4] labelPixmapRect = QRect(labelPixmapX, labelPixmapY, labelPixmapWidth, labelPixmapHeight) intersectedRect = self.pmapShowAreaRect.intersected( labelPixmapRect) if intersectedRect: pixmapTopLeftPoint, pixmapBottomRightPoint = intersectedRect.topLeft( ), intersectedRect.bottomRight() widgetTopLeftPointX, widgetTopLeftPointY = self.imageXY2WidgetXY( pixmapTopLeftPoint.x(), pixmapTopLeftPoint.y()) widgetTopLeftPoint = QPoint(widgetTopLeftPointX, widgetTopLeftPointY) widgetBottomRightPointX, widgetBottomRightPointY = self.imageXY2WidgetXY( pixmapBottomRightPoint.x(), pixmapBottomRightPoint.y()) widgetBottomRightPoint = QPoint(widgetBottomRightPointX, widgetBottomRightPointY) labelRect = QRect(widgetTopLeftPoint, widgetBottomRightPoint) self.painter.drawRect(labelRect) # 绘制标签名 labelrect = labelRect.getRect() textRect1 = QRect(labelrect[0], labelrect[1] - textHeight, textWidth, textHeight) # self.painter.drawRect(textRect1) self.painter.drawText(textRect1, Qt.AlignCenter, text) self.painter.end()
class Ui_ScShot_Logic(QWidget, Ui_ScShot): """ 截屏逻辑: 1、一打开截屏,就先创建屏幕截图pixScreenshot,并设置为主窗口的背景,并设置窗口无标题栏。再创建一个QWidget(wTop), 用来作为全屏的阴影遮盖,设置背景样式rgba的透明,它的大小以及主窗口的大小都是全屏大小(和全屏截图一样大)。功能 按钮容器wFunc,以及其它功能不作介绍,代码里有注释。 2、设置鼠标按下、移动,释放,来画出一个矩形框。在移动的时候设置标记(flagDrawing)为True,并self.update刷新界面,在刷新 界面时就能设置画笔和画刷来画出所要截图的范围 3、这第三步,其实有一部分在第一处就要设置。这对我来说是个难点,研究了两天,才瞎猫碰到死耗子搞成了。原本在网上复制的 截屏代码,竟然矩形选框内被穿透了,直接可以操作内部(此程序下面此范围内),很是让人无语。才研究两天,总算总算解决了。 此程序就是用pyqt5的setMask遮罩效果来完成对我来说主要的功能的。 在初始化处先创建一个QBitmap(blackMask),并填充成黑色,然后设置QWidget(wTop)的遮罩为blackMask。这里简单说一下,如果 在遮罩的地方用白色画刷涂的地方会失去遮罩(也就是wTop的背景),显示出下层窗口(窗口已经设置为全屏截图)的图片。 用黑色画刷涂的话,就是显示出wTop的背景。这里就样photoShop中的那个蒙版效果,原理是一样的。重要处在paintEvent事件中, 已经有注释。 """ def __init__(self, parent): super(Ui_ScShot_Logic, self).__init__() self.setupUi(self) # 加载设计师画的界面 self.p = parent # 主窗口设置 self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) # 隐藏标题栏 self.pixPrtSc = QApplication.primaryScreen().grabWindow(QApplication.desktop().winId()) # 截取整个屏幕(QPixmap类型) self.resize(self.pixPrtSc.size()) # 设置主窗口大小 p = QPalette() p.setBrush(self.backgroundRole(), QBrush(self.pixPrtSc)) self.setPalette(p) # 设置主窗口背景 self.flagDrawing = False # 主窗口的鼠标拖动标记,已经为子 self.wid = QLabel(self) self.wid.lower() # self.wid.raise_() # 最上层 self.wid.resize(self.size()) self.wid.move(0, 0) self.wid.setStyleSheet('border:3px solid #00FFFF;') # self.wid.hide() # 阴影容器设置 self.wTop.resize(self.size()) # 设置wTop也为屏幕大小 self.blackMask = QBitmap(self.size()) # 创建位图,全屏大小 self.blackMask.fill(Qt.black) # 填充位图为全黑。显示效果为原本wTop的背影,如果全白,相当于把wTop擦掉了。 self.wTop.setMask(self.blackMask) # 设置self.wTop的遮罩为self.blackMask self.wTop.enterEvent = self.wTop_EnterEvent # 设置wTop的鼠标进入事件。事件内有详细注释。 self.flagWTopEnter = False # wTop的鼠标进入事件的标记 # 其它需要初始化的 self.btnOk.clicked.connect(self.slot_ScShot_btns) self.btnSaveAs.clicked.connect(self.slot_ScShot_btns) self.wFunc.hide() # 先隐藏功能按钮容器 self.wInfo.hide() # 本来可以不用隐藏,再让后面显示,但是那样它会闪一下。因为原来的位置是在Qt设计师中乱放的。 self.strDpi = "0 x 0" self.flag = False # lab = QLabel('aaa', self.wTop) # lab.resize(300, 300) # lab.setStyleSheet('background:red;') def wTop_EnterEvent(self, e): """ 鼠标进入wTop子QWidget内,为了处理一打开截屏界面wInfo初始跟随鼠标状态,只需要一次,因为有self的鼠标 mouseMoveEvent处理后续动作。之所以要做一个标记flagWTopEnter为False才有动作,是因为在截图时,画的矩形 选区内是self的焦点,之外才是wTop的焦点。鼠标在矩形内外来回移动会多次处理此事件动作,关键是此动作和 self的鼠标移动件事有冲突,都在处理wInfo的鼠标跟随。目前只想到这种方法解决。 """ if not self.flagWTopEnter: # 只有self.flagWTopEnter=False时,not self.flagWTopEnter 才为真 self.flagWTopEnter = True self.imgPrtSc = self.pixPrtSc.toImage() self.method_wInfo(e.globalPos().x(), e.globalPos().y()) self.wInfo.show() # rect = QRect(e.globalPos().x() - 13, e.globalPos().y() - 10, 114, 85) # 截取的范围 # copyZoomIn = self.pixPrtSc.copy(rect) # self.labInfoZoomIn.setPixmap(copyZoomIn) def method_wInfo(self, pointX, pointY): """QWidget(wInfo)的移动,以及wInfo内的QLebal(labInfoZoomIn)的图片设置""" self.wInfo.move(pointX + 5, pointY + 20) color = self.imgPrtSc.pixelColor(pointX, pointY) self.strRgb = str(color.getRgb()[:-1]) self.textEdInfoRgb.setText(f"DPI:({self.strDpi})<br/>RGB:{self.strRgb}") # 13 10 # 参数32,24,是矩形的宽高,是要QLabel(labInfoZoomIn)设置的图片,因为在设计师中已经设置setScaledContents为True, # 所以它放比它小的图片会放大。而pointX-14和pointY-10,是矩形的左上角位置,需要减多少,是看原图大小的宽高除以2, # 再减去十字线(宽4px)的一半(32/2-2=14,24/2-2=10。labInfoZoomIn的尺寸是116x84 # 这样,labInfoZoomIn在显示图片的时候,十字交差处才会是鼠标指针点的位置。 rect = QRect(pointX-14, pointY-10, 32, 24) # 截取的范围 copyZoomIn = self.pixPrtSc.copy(rect) self.labInfoZoomIn.setPixmap(copyZoomIn) def slot_ScShot_btns(self): sender = self.sender() filePath = self.p.lineEdFilePath.text() rq = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) self.copyPixPrtSc = self.pixPrtSc.copy(self.rect) # 截取矩形区内的图片 PlaySound('prtSc.wav', flags=1) if sender == self.btnOk: if not os.path.exists(filePath): # 如果此路径没有此文件夹,就创建一个 os.mkdir(filePath) imgPath = f"{filePath}/{rq}.png" self.copyPixPrtSc.save(imgPath, format='png', quality=100) elif sender == self.btnSaveAs: currentPath = filePath + f"/{rq}.png" fileName, _ = QFileDialog.getSaveFileName(self, "另存为", currentPath, f"PNG File(*.png);;All Files(*)") if fileName: self.copyPixPrtSc.save(fileName, format='png', quality=100) self.close() def paintEvent(self, event): if self.flag: pointX = self.endPoint.x() pointY = self.endPoint.y() self.method_wInfo(pointX, pointY) # 调用移动方法 if self.flagDrawing: self.mask = self.blackMask.copy() # 必须要拷贝,其实我也不是很理解这句为何。 pp = QPainter(self.mask) # 参数一定要是拷贝的QPixmap(self.mask) pen = QPen() # 创建画笔 Qt.green, 13, Qt.DashDotLine, Qt.RoundCap, Qt.RoundJoin pen.setStyle(Qt.NoPen) pp.setPen(pen) brush = QBrush(Qt.white) # 创建画刷 pp.setBrush(brush) rect = QRect(self.startPoint, self.endPoint) pp.drawRect(rect) # 画矩形 self.wTop.setMask(QBitmap(self.mask)) # 是wTop设置遮罩,不是主窗口。不然会穿透的。 self.strDpi = f"{abs(rect.width())} x {abs(rect.height())}" # self.wid.setStyleSheet('border:2px dashed #00FFFF;') # 改变边宽和样式(虚线) # self.wid.setGeometry(rect.adjusted(-2, -2, 2, 2)) # 上下左右都往外偏移2px,因为上面设置border为2px # self.wid.setGeometry( rect.x()-2, rect.y()-2,abs(rect.width())+2,abs(rect.height())+2) # 上下左右都往外偏移2px,因为上面设置border为2px try: sX, sY, eX, eY = self.startPoint.x(), self.startPoint.y(), self.endPoint.x(), self.endPoint.y() p2 = QPainter(self) pen2 = QPen(QColor('#00FFFF'), 1) p2.setPen(pen2) p2.drawRect(rect) # 下面这四句忘了本来要做什么的了 # p2.fillRect(rect, QColor('background:rgba(0,0,0,100);')) # rect.adjust(50, 50, -50, -50) # p2.drawRect(rect) # p2.fillRect(rect, Qt.red) listPointRect = [(sX, sY), (sX + (eX - sX) / 2, sY), (eX, sY), (eX, sY + (eY - sY) / 2), (eX, eY), (sX + (eX - sX) / 2, eY), (sX, eY), (sX, sY + (eY - sY) / 2)] for x, y in listPointRect: p2.drawRect(x - 3, y - 3, 6, 6) p2.fillRect(x - 3, y - 3, 6, 6, QBrush(QColor('#00FFFF'))) # p2.begin(self) # path = QPainterPath() # path.addRect(QRectF(self.startPoint, self.endPoint)) # self.wid.setGeometry(QRect(*path.controlPointRect().getRect()).adjusted(-20, -20, 20, 20)) # p2.drawRect(QRectF(*(sX, sY), *(sX + (eX - sX) / 2, sY))) # listPointRect = [(sX, sY), (sX+(eX-sX)/2, sY), (eX, sY), (eX, sY+(eY-sY)/2), # (eX, eY), (sX+(eX-sX)/2, eY), (sX, eY), (sX, sY+(eY-sY)/2)] # path2 = QPainterPath() # for x, y in listPointRect: # path2.addRect(x-3, y-3, 6, 6) # p2.fillPath(path2, QBrush(QColor('#00FFFF'))) # path.connectPath(path2) # 连接两个闭合路径 # path.translate(50, 50) # 偏移到某点 # p2.drawPath(path) # self.wid.setStyleSheet('border:none;') # p2.end() except Exception as e: print(e) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: # self.wid.hide() self.wTop.setStyleSheet('background:rgba(0,0,0,100);') # 设置背景透明度,阴影效果。鼠标按下时再出现 self.wInfo.show() self.startPoint = event.pos() self.endPoint = self.startPoint self.wFunc.hide() # 鼠标按下时隐藏功能按钮容器 self.flagDrawing = True elif event.button() == Qt.RightButton: self.close() def mouseMoveEvent(self, event): """ 必须为子控件设置鼠标跟踪setMouseTracking(True),不然鼠标在控件上时,就不再追踪了。 已经在Qt设计师中设置好了 """ self.flag = True self.endPoint = event.pos() self.update() # self.pointX = event.globalPos().x() # event.pos()也行 # self.pointY = event.globalPos().y() # self.flag = True # # self.method_wInfo_move(pointX, pointY) # 调用移动方法 # if self.flagDrawing: # self.endPoint = event.pos() # self.update() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.endPoint = event.pos() self.rect = QRect(self.startPoint, self.endPoint) # 截取的范围 shotX, shotY, shotWidth, shotHeight = self.rect.getRect() wFuncWidth, wFuncHeight = self.wFunc.width(), self.wFunc.height() # 以下if语句是判断鼠标释放后,最后一点到窗口边缘时,功能按钮容器超界问题 if shotWidth < 0: moveX = shotX + shotWidth - (wFuncWidth + shotWidth) # 这里width是负数,这里用+号相当于减去 else: moveX = shotX + shotWidth - wFuncWidth if shotHeight < 0: moveY = shotY else: moveY = shotY + shotHeight if moveX < 0: moveX = 0 if self.pixPrtSc.height() - moveY < wFuncHeight: moveY = moveY - shotHeight - wFuncHeight self.wFunc.move(moveX, moveY) self.wFunc.show() # 鼠标释放时显示功能按钮容器 self.wInfo.hide() # 鼠标释放时隐藏信息显示容器 self.flagDrawing = False self.flag = False # def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close()