前言
记录本人常用的PyQt5编程,方便自身查阅,也许有缘能帮到网友。
持续更新中......
一、点击按钮切换窗口(回车登录)
self.ui.pushButton_login.clicked.connect(self.open_mainwindow)
写在初始化函数里。
def keyPressEvent(self, event): # 回车登录
if str(event.key()) == '16777220' or str(event.key()) == '16777221':
self.open_mainwindow()
def open_mainwindow(self):
if self.ui.lineEdit_username.text() == 'user' or self.ui.lineEdit_username.text() == 'USER':
if self.ui.lineEdit_password.text() == '123':
win.close()
import pyqt5_mainwindow as main # 等满足条件后再导入main类(mainwindow已经经过QMainWindow类编辑)
self.one = main.WinMain()
self.one.show()
self.one.ui.stackedWidget_show.setCurrentIndex(0)
else:
import pyqt5_message as mess # 等满足条件后再导入mess类(mess已经经过QMainWindow类编辑)
self.two = mess.WinMessage()
self.two.ui.label.setText('账户名或者密码错误!')
self.two.show()
self.ui.lineEdit_password.setText('')
写在类方法里就行。
二、两个或者多个窗口传递参数
这个对于开发应用来说十分必要,关键函数pyqtSignal
先举一个简单的例子:
通过应用小窗口输入账号密码登录,成功登录后关闭原窗口打开大窗口,大窗口有重新登录至工程师模式的按钮,点击该按钮不关闭大窗口并生成新的登录窗口,登录成功后大窗口改变界面。
参考 一、点击按钮切换窗口(回车登录)
,打开新窗口都不需要通讯,满足条件即可。
重点在于工程师模式登录成功后大窗口改变界面
,并非简单粗暴关闭原窗口再打开。
在需要发送指令的类里面添加pyqtSignal:
from PyQt5.QtCore import pyqtSignal
class WinLogin(QMainWindow):
signal_confirm = pyqtSignal(int) # 放在最开头,别加self
在类方法里写入当达成什么条件后会发送信息:
def open_mainwindow(self):
if self.ui.lineEdit_username.text() == 'ADMIN' or self.ui.lineEdit_username.text() == 'admin':
if self.ui.lineEdit_password.text() == 'emins' or self.ui.lineEdit_password.text() == 'EMINS':
self.flag = 1
self.signal_confirm.emit(self.flag) # 达成条件,发送flag=1的信息
else:
import pyqt5_message as mess
self.two = mess.WinMessage()
self.two.ui.label.setText('请输入工程师模式账号!')
self.two.show()
self.ui.lineEdit_password.setText('')
在需要接受到信息的类方法里面添加接收反应:
def change_engmode(self):
import pyqt5_login_eng as ple
self.one = ple.WinLogin()
self.one.show()
self.one.signal_confirm.connect(self.enter_engmode)
def enter_engmode(self, flag):
if flag == 1:
self.ui.stackedWidget_show.setCurrentIndex(2)
self.one.close()
三、正则化判断输入
在用户输入内容时,往往需要限制输入,为何呢?
举个例子,你程序的某个输入框本来只能处理int数据,这时用户输入了**&&等符号并提交,那么你的程序就会直接奔溃。
于是需要了解正则化判断输入:可以直接看这篇文章——【pyqt5】 关于QT限制输入约束的正则表达式详解和一些常用表达式
若是对正则化感兴趣,可以查看我写的另一篇文章:python常用正则化表达
导入库:
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtCore import QRegExp
在类初始化方法限定username输入:
self.username_validator = QRegExpValidator(QRegExp(r'\b[a-zA-Z]{1,5}\b'))
self.ui.lineEdit_username.setValidator(self.username_validator)
四、自定义QLabel缩放和框选图片
有所参考:PyQt5实现图片缩放、旋转
在PyUIC生成的py文件里新建一个QWidget类来代替QLabel
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QStyleOption, QStyle
from PyQt5.QtGui import QPainter, QPixmap, QColor, QPen
from PyQt5.QtCore import pyqtSignal, QPoint, Qt, qAbs, QRect
# 定义可伸缩QLabel
class MyLabel(QWidget): # 不可用QMainWindow,因为QLabel继承自QWidget
signal_roi = pyqtSignal(list)
def __init__(self, img_pth, img_state):
super(MyLabel, self).__init__()
self.imgPixmap = QPixmap(img_pth) # 载入图片,不覆写,显示的图片都用scaledImg表达
self.init_ui_face()
self.init_img()
self.scale_width = int(self.init_img_width / 10) # 定义缩放最小单位
self.scale_height = int(self.init_img_height / 10)
self.scaledImg = self.imgPixmap.scaled(self.init_img_size) # 初始化缩放图
self.singleOffset = QPoint(0, 0) # 初始化偏移值
self.img_state = img_state # True是移动,False是截图
self.isLeftPressed = False # 图片被点住(鼠标左键)标志位
self.isImgLabelArea = True # 鼠标进入label图片显示区域
self.isCutPressLeft = False # 图片选择标志
self.isSentROI = False # 发送坐标标志
def init_ui_face(self):
# 初始化界面大小
self.desktop = QApplication.desktop()
self.screenRect = self.desktop.screenGeometry()
self.screenheight = self.screenRect.height()
self.screenwidth = self.screenRect.width()
self.open_height = int(self.screenheight * 0.6) - 114
self.open_width = int(self.screenwidth * 0.4) - 18
self.resize(self.open_width, self.open_height)
def init_img(self):
# 初始化图片尺寸(等比例填充全满QLabel,会有部分看不见)
if self.imgPixmap.width() > self.imgPixmap.height():
self.ratio = self.imgPixmap.width() / self.imgPixmap.height()
self.init_img_height = self.width() / self.ratio
self.init_img_width = self.width()
self.init_img_size = QtCore.QSize(self.init_img_width, self.init_img_height)
else:
self.ratio = self.imgPixmap.width() / self.imgPixmap.height()
self.init_img_height = self.height()
self.init_img_width = self.height() * self.ratio
self.init_img_size = QtCore.QSize(self.init_img_width, self.init_img_height)
# def init_img(self):
# # 初始化图片尺寸(等比例最大放置于QLabel,全图都能看)
# self.img_ratio = self.imgPixmap.width() / self.imgPixmap.height()
# self.label_ratio = self.width() / self.height()
# if self.img_ratio > self.label_ratio:
# self.init_img_height = self.imgPixmap.height() * self.width() / self.imgPixmap.width()
# self.init_img_width = self.width()
# self.init_img_size = QtCore.QSize(self.init_img_width, self.init_img_height)
#
# else:
# self.init_img_height = self.height()
# self.init_img_width = self.imgPixmap.width() * self.height() / self.imgPixmap.height()
# self.init_img_size = QtCore.QSize(self.init_img_width, self.init_img_height)
def paintEvent(self, event):
self.painter = QPainter()
self.painter.begin(self) # 开始重绘
shadowColor = QColor(0, 0, 0, 100) # 黑色半透明
penColor = QColor(0, 0, 255) # 画笔颜色
self.painter.setPen(QPen(penColor, 1, Qt.SolidLine, Qt.RoundCap)) # 设置画笔,蓝色,1px大小,实线,圆形笔帽
self.painter.drawPixmap(self.singleOffset, self.scaledImg) # 在offset点上绘制缩放图
# 找到缩放图的bottom right
self.scaledImg_br = QPoint(self.scaledImg.width(), self.scaledImg.height()) + self.singleOffset
self.scaledImg_rect = QRect(self.singleOffset, self.scaledImg_br) # 缩放图的坐标
self.painter.fillRect(self.scaledImg_rect, shadowColor) # 绘制阴影
# 截取状态下才进行截图
if self.isCutPressLeft is True:
pickRect = self.getRectangle(self.beginPosition, self.endPosition) # 获得要截图的矩形框
# 进行offset修正
self.cut_rect = QRect(pickRect.topLeft() - self.singleOffset, pickRect.bottomRight() - self.singleOffset)
# 设定在缩放图内截取才有效
if self.cut_rect.height() > 0 and self.cut_rect.width() > 0:
self.captureImage = self.scaledImg.copy(self.cut_rect) # 捕获缩放图矩形框内的图片
self.painter.drawPixmap(pickRect.topLeft(), self.captureImage) # 填充截图的图片
self.painter.drawRect(pickRect) # 画矩形边框
self.painter.end()
def getRectangle(self, beginPoint, endPoint):
# 限制画框区域
pickRectWidth = int(qAbs(beginPoint.x() - endPoint.x()))
pickRectHeight = int(qAbs(beginPoint.y() - endPoint.y()))
pickRectLeft = beginPoint.x() if beginPoint.x() < endPoint.x() else endPoint.x()
pickRectLeft = pickRectLeft if pickRectLeft > self.singleOffset.x() else self.singleOffset.x()
pickRectTop = beginPoint.y() if beginPoint.y() < endPoint.y() else endPoint.y()
pickRectTop = pickRectTop if pickRectTop > self.singleOffset.y() else self.singleOffset.y()
pickRectRight = pickRectLeft + pickRectWidth if pickRectLeft + pickRectWidth < self.singleOffset.x() \
+ self.scaledImg.width() else self.singleOffset.x() + self.scaledImg.width()
pickRectBottom = pickRectTop + pickRectHeight if pickRectTop + pickRectHeight < self.singleOffset.y() \
+ self.scaledImg.height() else self.singleOffset.y() + self.scaledImg.height()
pickRectWidth = pickRectRight - pickRectLeft
pickRectHeight = pickRectBottom - pickRectTop
pickRect = QRect(pickRectLeft, pickRectTop, pickRectWidth, pickRectHeight)
# 避免高度宽度为0时候报错
if pickRectWidth == 0:
pickRect.setWidth(2)
if pickRectHeight == 0:
pickRect.setHeight(2)
return pickRect
def mousePressEvent(self, event):
if self.img_state:
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
if event.buttons() == QtCore.Qt.LeftButton:
self.isLeftPressed = True
self.preMousePosition = event.pos()
else:
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
if event.button() == QtCore.Qt.LeftButton:
self.isCutPressLeft = True
self.beginPosition = event.pos()
def zoom_out(self):
self.scaledImg = self.imgPixmap.scaled(self.scaledImg.width() + self.scale_width,
self.scaledImg.height() + self.scale_height)
self.repaint()
def zoom_in(self):
self.scaledImg = self.imgPixmap.scaled(self.scaledImg.width() - self.scale_width,
self.scaledImg.height() - self.scale_height)
self.repaint()
def wheelEvent(self, event):
angle = event.angleDelta() / 8
angleY = angle.y()
if angleY > 0:
self.scaledImg = self.imgPixmap.scaled(self.scaledImg.width() + self.scale_width,
self.scaledImg.height() + self.scale_height)
newWidth = event.x() - (self.scaledImg.width() * (event.x() - self.singleOffset.x())) \
/ (self.scaledImg.width() - self.scale_width)
newHeight = event.y() - (self.scaledImg.height() * (event.y() - self.singleOffset.y())) \
/ (self.scaledImg.height() - self.scale_height)
self.singleOffset = QPoint(newWidth, newHeight)
self.repaint()
else:
if self.scaledImg.width() > self.scale_width and self.scaledImg.height() > self.scale_height:
self.scaledImg = self.imgPixmap.scaled(self.scaledImg.width() - self.scale_width,
self.scaledImg.height() - self.scale_height)
newWidth = event.x() - (self.scaledImg.width() * (event.x() - self.singleOffset.x())) \
/ (self.scaledImg.width() + self.scale_width)
newHeight = event.y() - (self.scaledImg.height() * (event.y() - self.singleOffset.y())) \
/ (self.scaledImg.height() + self.scale_height)
self.singleOffset = QPoint(newWidth, newHeight)
self.repaint()
def mouseReleaseEvent(self, event):
if self.img_state:
if event.buttons() == QtCore.Qt.LeftButton:
self.isLeftPressed = False
else:
if event.buttons() == QtCore.Qt.LeftButton:
self.endPosition = event.pos()
self.isCutPressLeft = False
self.isSentROI = True
if event.button() == QtCore.Qt.RightButton:
self.singleOffset = QPoint(0, 0)
self.init_img()
self.scaledImg = self.imgPixmap.scaled(self.init_img_size)
self.repaint()
def mouseMoveEvent(self, event):
if self.img_state:
if self.isLeftPressed:
self.endMousePosition = event.pos() - self.preMousePosition
self.singleOffset = self.singleOffset + self.endMousePosition
self.preMousePosition = event.pos()
self.repaint()
else:
if self.isCutPressLeft is True:
self.endPosition = event.pos()
self.update()
def calculate_coordinate(self):
# 计算并发送所选坐标对应最初图片的坐标值
if self.isSentROI:
self.scale_ratio = self.imgPixmap.width() / self.scaledImg.width()
self.roi_top = int(self.cut_rect.top() * self.scale_ratio)
self.roi_left = int(self.cut_rect.left() * self.scale_ratio)
self.roi_right = int(self.cut_rect.right() * self.scale_ratio)
self.roi_bottom = int(self.cut_rect.bottom() * self.scale_ratio)
self.roi = [self.roi_left, self.roi_top, self.roi_right, self.roi_bottom]
self.signal_roi.emit(self.roi)
放入UI的object类内
self.label = MyLabel(img_pth, self.img_state)
# self.label.setMouseTracking(False) # 若有设置鼠标跟踪的记得关闭
可以在主程序的类内初始化函数内加入pysignal接收端,用于接收框选的坐标值
self.ui.label.signal_roi.connect(self.save_roi)