加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Widgets.py 12.09 KB
一键复制 编辑 原始数据 按行查看 历史
执明神君 提交于 2021-03-02 23:00 . 更新一键打开功能
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from math import pi, cos, sin
# import cv2
# from glob import glob
blueStyle = 'background-color:#3daee9;border-width:1px'
darkStyle = 'background-color:#31363b;border-width:1px'
class Label(QLabel):
def __init__(self, text):
super(Label, self).__init__()
self.setText(text)
self.setAlignment(Qt.AlignCenter)
class Slider(QSlider):
currentValue = Signal(int)
def __init__(self, min, max):
super(Slider, self).__init__()
self.setOrientation(Qt.Horizontal)
self.min, self.max = min, max
self.setMinimum(min)
self.setMaximum(max)
def mousePressEvent(self, event):
self.changeValue(event)
def mouseMoveEvent(self, event):
self.changeValue(event)
def changeValue(self, event):
x = event.x()
if x < 0:
x = 0
if x > self.width():
x = self.width()
value = int(self.min + x / self.width() * (self.max - self.min))
self.setValue(value)
self.currentValue.emit(value)
def wheelEvent(self, event):
pass
class OptionWidget(QWidget): # 调节页
mirrored = Signal()
def __init__(self):
super(OptionWidget, self).__init__()
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setWindowTitle('透明度和图片缩放')
self.setFixedSize(500, 175)
layout = QGridLayout(self)
layout.addWidget(Label('透明'), 0, 0, 1, 1)
self.opacitySlider = Slider(10, 100)
self.opacitySlider.setValue(100)
layout.addWidget(self.opacitySlider, 0, 1, 1, 5)
self.percentLabel = Label('100%')
layout.addWidget(self.percentLabel, 0, 6, 1, 1)
layout.addWidget(Label('缩放'), 1, 0, 1, 1)
self.scaleSlider = Slider(0, 34)
self.scaleSlider.setTickInterval(1)
# self.scaleSlider.setTickPosition(QSlider.TicksAbove)
layout.addWidget(self.scaleSlider, 1, 1, 1, 5)
self.scaleLabel = Label('x0.04')
layout.addWidget(self.scaleLabel, 1, 6, 1, 1)
layout.addWidget(Label('旋转'), 2, 0, 1, 1)
self.rotateSlider = Slider(-180, 180)
self.rotateSlider.setTickInterval(1)
self.rotateSlider.currentValue.connect(self.setRotateLabel)
layout.addWidget(self.rotateSlider, 2, 1, 1, 5)
self.rotateLabel = Label('0 度')
layout.addWidget(self.rotateLabel, 2, 6, 1, 1)
self.mirrorToken = False
self.mirrorButton = QPushButton('镜像')
self.mirrorButton.clicked.connect(self.setMirrored)
layout.addWidget(self.mirrorButton, 3, 0, 1, 1)
def setRotateLabel(self, value):
self.rotateLabel.setText('%s 度' % value)
def setMirrored(self):
self.mirrorToken = not self.mirrorToken
if self.mirrorToken:
self.mirrorButton.setStyleSheet(blueStyle)
else:
self.mirrorButton.setStyleSheet(darkStyle)
self.mirrored.emit()
class ImageWidget(QLabel): # 画布控件 自定义QLabel实现
resizeSignal = Signal(QSize) # 画框大小变化信号
openSignal = Signal() # 打开图片选择窗信号
moveSignal = Signal(QPoint) # 移动全局坐标偏移量
rightClickSignal = Signal(QPoint) # 右键点击
leftClickSignal = Signal() # 左键点击
scaleSignal = Signal(list) # 缩放信号
mirrorSignal = Signal() # 镜像信号
def __init__(self, parent):
super(ImageWidget, self).__init__(parent)
# self.setFrameShape(QFrame.Box) # 本来想给画布加上边框 效果不好看取消了
# self.setStyleSheet('border:3px dot-dot-dash #cfcfd0') # dashed|dot-dash|dot-dot-dash|dotted|double|solid
self.image = None
self.scaleRates = [i / 100 for i in range(4, 20)] + [i / 10 for i in range(2, 21)]
self.rotateAngle = 0
self.sin = 0 # sin值
self.cos = 1 # cos值
self.rightButtonPressed, self.leftButtonPressed = False, False
self.point = QPoint(0, 0)
self.scaledImage = QPixmap()
self.pressTimeoutCount = 0
self.pressTimer = QTimer()
self.pressTimer.timeout.connect(self.longPress)
def paintEvent(self, event): # 重绘事件 响应画布拖拽 旋转等操作
painter = QPainter()
painter.setRenderHint(QPainter.SmoothPixmapTransform, QPainter.Antialiasing)
painter.begin(self)
if self.rotateAngle: # 判断旋转
painter.translate(self.width() / 2, self.height() / 2)
painter.rotate(self.rotateAngle)
painter.translate(-self.width() / 2, -self.height() / 2)
painter.drawPixmap(self.point, self.scaledImage) # 根据偏移顶点重新绘制scaledImage
painter.end()
def setImagePath(self, image='', width=400, initMirror=True): # 设置原始图片 以及初始化scaledImage对象
self.rotateAngle = 0
if image: # 原始图片有效 则加载进self.image(QPixmap对象)
if type(image) == str: # 路径导入
self.image = QPixmap(image)
elif type(image) == QPixmap: # 剪切板粘贴
self.image = image
if self.image.width(): # 判断导入图片是否有宽度值
for self.scaleIndex, scaleRate in enumerate(self.scaleRates): # 计算合适的缩放比率并发射信号给主进程设置缩放页的滑条
if self.image.width() * scaleRate >= width:
self.scaleSignal.emit([self.scaleIndex, scaleRate])
break
self.scaledImage = self.image.scaled(self.image.width() * scaleRate, self.image.height() * scaleRate) # 缩放
self.resizeSignal.emit(self.scaledImage.size())
if initMirror:
self.mirrorSignal.emit()
self.point = QPoint(0, 0) # 初始化顶点坐标
self.repaint() # 重绘
def mousePressEvent(self, event): # 鼠标点击事件 要判断左键和右键 功能不同
self.mouseMove = False
self.startPos = event.pos()
if event.button() == Qt.RightButton: # 右键标志位 之后要判断是拖拽还是右键菜单
self.setCursor(Qt.ClosedHandCursor) # 抓取图标
self.rightButtonPressed = True
else: # 左键
if not self.image: # 没加载图片的时候发射信号弹出图片选择窗
self.openSignal.emit()
else: # 左键标志位 开始长按计时器
self.setCursor(Qt.SizeAllCursor) # 移动图标
self.longPressPoint = event.pos()
self.pressTimeoutCount = 0 # 重置长按计数
self.pressTimer.start(750) # 定时器间隔
self.leftButtonPressed = True
def longPress(self): # 长按计时器触发 用于数位板适配
self.pressTimeoutCount += 1
if self.pressTimeoutCount == 1: # 长按超时第1次变为拖拽画布
self.setCursor(Qt.ClosedHandCursor)
self.rightButtonPressed = True
self.leftButtonPressed = False
elif self.pressTimeoutCount == 2: # 长按超时第2次改为弹出菜单
self.pressTimer.stop()
self.rightClickSignal.emit(self.longPressPoint)
def mouseReleaseEvent(self, event): # 鼠标松开 要判断左键还是右键 功能不同
self.setCursor(Qt.ArrowCursor)
self.pressTimer.stop() # 停止长按计时
self.rightButtonPressed = False
self.leftButtonPressed = False
if event.button() == Qt.RightButton:
if not self.mouseMove: # 原地松开 发射信号弹出右键菜单
self.rightClickSignal.emit(event.pos())
else:
if not self.mouseMove:
self.leftClickSignal.emit()
def mouseMoveEvent(self, event): # 鼠标移动事件 要判断左键还是右键 功能不同
self.pressTimer.stop()
self.mouseMove = True
if self.rightButtonPressed: # 右键按住拖动画布
if self.image:
if self.rotateAngle:
newX, newY = event.pos().x(), event.pos().y()
oldX, oldY = self.startPos.x(), self.startPos.y()
deltaX = newX - oldX
deltaY = newY - oldY
newDeltaX = deltaY * self.sin + deltaX * self.cos
newDeltaY = deltaY * self.cos - deltaX * self.sin
newPoint = self.startPos + QPoint(newDeltaX, newDeltaY)
else:
newPoint = event.pos()
moveDelta = newPoint - self.startPos # 计算偏移量
point = self.point + moveDelta
imageX, imageY = point.x(), point.y()
imageW, imageH = self.scaledImage.width(), self.scaledImage.height()
parentW, parentH = self.parent().width(), self.parent().height()
if imageX + imageW < 5 or imageY + imageH < 5 or imageX > parentW - 5 or imageY > parentH - 25:
pass
else:
self.point = point
self.startPos = event.pos()
self.repaint()
elif self.leftButtonPressed: # 左键按住发射位移量给主进程移动全局坐标
moveDelta = event.pos() - self.startPos # 计算偏移量
self.moveSignal.emit(moveDelta)
def wheelEvent(self, event): # 滚轮事件缩放画布 判断往上滚还是往下滚
if self.image:
eventX, eventY = event.x(), event.y() # 获取鼠标缩放坐标
pointX, pointY = self.point.x(), self.point.y()
oldWidth, oldHeight = self.scaledImage.width(), self.scaledImage.height()
if pointX <= eventX <= pointX + oldWidth and pointY <= eventY <= pointY + oldHeight: # 判断鼠标在画布内
if event.angleDelta().y() < 0 < self.scaleIndex: # 防止越界
self.scaleIndex -= 1
elif event.angleDelta().y() > 0 and self.scaleIndex < len(self.scaleRates) - 1: # 防止越界
self.scaleIndex += 1
scaleRate = self.scaleRates[self.scaleIndex] # 获取缩放比率
self.scaledImage = self.image.scaled(self.image.width() * scaleRate, self.image.height() * scaleRate)
newWidth, newHeight = self.scaledImage.width(), self.scaledImage.height()
w = eventX - newWidth * (eventX - pointX) / oldWidth
h = eventY - newHeight * (eventY - pointY) / oldHeight
self.point = QPoint(w, h) # 设置顶点坐标
self.repaint() # 重绘
self.scaleSignal.emit([self.scaleIndex, scaleRate]) # 发射缩放倍数
def sliderScale(self, index): # 调节页滑条缩放
if self.image:
self.scaleIndex = index
scaleRate = self.scaleRates[self.scaleIndex]
self.scaledImage = self.image.scaled(self.image.width() * scaleRate, self.image.height() * scaleRate)
newWidth, newHeight = self.scaledImage.width(), self.scaledImage.height()
self.point = QPoint((self.width() - newWidth) / 2, (self.height() - newHeight) / 2)
self.repaint() # 重绘
# self.scaleSignal.emit([self.scaleIndex, scaleRate])
def rotate(self, value): # 调节页滑条旋转
if self.image:
self.rotateAngle = value # 修改旋转度数
theta = self.rotateAngle / 180 * pi
self.sin = sin(theta) # 更新旋转度数
self.cos = cos(theta) # 更新旋转度数
self.repaint() # 重绘
def mirror(self):
if self.image: # 图片有效
if self.image.width(): # 图片有宽度
tempImage = self.image.toImage()
tempImage = tempImage.mirrored(True, False) # 镜像
self.image = QPixmap.fromImage(tempImage) # 修改原始图像
scaleRate = self.scaleRates[self.scaleIndex] # 获取缩放比率
self.scaledImage = self.image.scaled(self.image.width() * scaleRate, self.image.height() * scaleRate)
self.repaint()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化