Python界面设计——GUI编程之PyQt5

Posted 码字小萌新♡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python界面设计——GUI编程之PyQt5相关的知识,希望对你有一定的参考价值。

文章目录

一. PyQt5基础

🔰常用模块:

  1. QtWidgets:包含了一整套UI元素控件,用于建立符合系统风格的界面;
  2. QtGui:涵盖了多种基本图形功能的类(字体, 图形,图标,颜色);
  3. QtCore:涵盖了包的核心的非GUI功能(时间,文件,目录,数据类型,文本流,链接,线程进程);

(一) 窗口显示

import sys  # 系统内置类
from PyQt5.Qt import *  # 主要包含了我们常用的一些类,汇总到了一块

if __name__ == '__main__':
	# 创建一个应用程序对象
	app = QApplication(sys.argv)
	# 创建一个空白控件(窗口)
	window = QWidget()
	# 设置窗口标题
	window.setWindowTitle("计时器")
	# 设置窗口尺寸
	window.resize(500, 500)
	# 移动窗口位置
	window.move(200, 200)
	# 创建label控件
	label = QLabel(window)
	# 为控件设置文本
	label.setText("hello")
	# 移动控件的位置
	label.move(160, 160)
	# 显示窗口
	window.show()
	# 进入程序的主循环,并通过exit函数确保主循环安全结束
	sys.exit(app.exec_())


(二) PyQt5程序结构分析

1. 导入需要的包和模块

from PyQt5.Qt import *
import sys  

2. 创建一个应用程序对象

# 创建一个应用程序对象
app = QApplication(sys.argv)

3. 控件的操作

🔰创建控件,设置控件(大小,位置,样式),事件,信号的处理

3.1 创建控件

🔰当我们创建一个控件之后,如果这个控件没有父控件,则把它当作顶层控件(窗口),系统会自动的给窗口添加一些装饰(标题栏),窗口控件具备一些特性(设置标题,图标);

# 创建一个空白控件(窗口)
window = QWidget()    
# 设置窗口标题
window.setWindowTitle("计时器")
# 设置窗口尺寸
window.resize(500, 500)
# 移动窗口位置
window.move(200, 200)

3.2 设置控件

🔰控件也可以作为一个容器(承载其他的控件);

# 创建label控件
label = QLabel(window)
# 为控件设置文本
label.setText("hello")
# 移动控件的位置
label.move(160, 160)

3.3 展示控件

🔰刚创建好一个控件之后,(这个控件没有什么父控件),默认情况况下不会被显示,只有手动的调用show(0才可以显示;
🔰如果这个控件有父控件,那么一般情况下,父控件展示后,子控件会自动展示;

# 显示窗口
window.show()

4. 应用程序的执行,进入到消息循环

🔰让整个程序开始执行,并且进入到消息循环(无限循环);
🔰检测整个程序所接受到的用户的交互信息;

# 进入程序的主循环,并通过exit函数确保主循环安全结束
sys.exit(app.exec_())

(三) 窗口属性设置

属性描述
window.serGeometry(300, 300, 300, 200)前两个参数定义了move;后两个参数定义了resize
window.move(400, 300)设置窗口左上顶端的坐标
window.resize(500, 500)设置窗口的宽度,高度
window.setWindowTitle(‘计算器’)设置窗口标题
window.setWindowIcon(QIcon(‘t1.jpg’))设置窗口logo


二. Pycham活动模板设置

🔰活动模板设置好以后,就可以快速生成所需模块;

🔰活动模板设置好以后,就可以快速生成所需模块;

(一) PyQt5的过程性代码结构模板

# 0. 导入需要的包和模块
from PyQt5.QtWidgets import *
import sys

# 1. 创建一个应用程序对象
app = QApplication(sys.argv)

# 2. 控件的操作
# 2.1 创建控件(创建窗口)
window = QWidget()
# 2.2 设置控件(窗口属性设置)
window.setWindowTitle("")
window.resize(500, 500)

# 设置内部控件
label = QLabel(window)
label.setText("")

# 2.3 展示控件
window.show()
# 3. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())


(二) PyQt5的面向对象代码结构模板

🔰下面两个模板是,第一个里面导入第二个,再运行第一个;

1. 主模块代码结构模板

# 0. 导入需要的包和模块
from PyQt5.QtWidgets import *
import sys

# 导入控件设置函数所在的模块
from 模块名 import Window

# 1. 创建一个应用程序对象
app = QApplication(sys.argv)

# 2. 控件的操作
# 2.1 创建控件(创建窗口及子控件)
# 从Menu模块中导入控件
window = Window()


# 2.3 展示控件
window.show()
# 3. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

2. 控件设置模块代码结构模板

from PyQt5.QtWidgets import *

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("")
        self.resize(500, 500)
        self.setup_ui()

    def setup_ui(self):
        
        label = QLabel(self)
        label.setText("")

# 在本模块内测试
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    window = Window()
    window.show()

    sys.exit(app.exec_())



三. QObject

(一) 对象名称,属性

1. API

API解析
setObjectName("唯一名称")给一个Qt对象设置一个名称,当作对象的ID来使用。
objectName()获取一个Qt对象的名称。
setProperty("属性名称",值)给一个Qt对象动态的添加一个属性与值。
property("属性名称")获取一个对象的属性值。
dynamicPropertyNames()获取一个对象中所有通过setProperty()设置的属性名称。

2. 应用场景

🔰用于qss的ID选择器,属性选择器,方便统一设置样式。

3. 案例演示

🔰普通样式设置:

label = QLabel(self)
label.setText("社会我顺哥")
# 样式设置
label.setStyleSheet("font-size: 20px; color: rad;")

🔰优化样式设置:
1)新建一个.qss后缀的样式文件,内写以下内容:

组件选择器

QLabel 
	font-size: 20px; color: rad;

表示只要是QLabel 组件,就将该样式作用在该组件上。前提是在.py文件里面写一下内容:

# qss样式表的引入
with open("Qobject.qss", "r") as f:
	qApp.setStyleSheet(f.read()

2)若.qss样式文件是类同如下内容

ID选择器

#notice 
	font-size: 20px; color: rad;

组件ID选择器

QLabel#notice 
	font-size: 20px; color: rad;

.py文件里面如下设置

# ID设置
label.setObjectName("notice")

这相当于是该组件的ID,类似于前端里面的类选择器
3)若.qss样式表文件是类同如下内容

组件属性值选择器

[notice_leve="warning"] 
    color:yellow;
   border-color: yellow;

.py文件里面如下设置

# 属性与属性值的设置
label.setProperty("notice_leve", "warning")

该选择器的主要应用场景是:同一个属性设置不同的属性值,每种属性值对应一类样式。


(二) 父子对象的操作

1. API

🔰setParent(parent): 设置父对象; 父对象只能设置一个 。

# 设置父对象
obj3.setParent(obj1)  # obj1 为 obj3 的父对象

🔰parent(): 获取父对象

# 获取父对象
obj3.parent()  

🔰children(): 获取所有直接子对象

# 获取所有子对象
obj1.children()  

🔰findchild(参数1, 参数2, 参数3): 获取某一个指定名称和类型的子对象

1)参数1: (类型: QObject; 类型元组: QPushButton, QLabel;)
2)参数2: (名称: notice; 可以省略)
3)参数3: (查找选项: [Qt.FindChildrenRecursively: 递归查找, 默认选项];[Qt.FindDirectChildrenOnly: 只查找直接子对象])

🔰findchildren(参数1, 参数2, 参数3): 获取某一个指定名称和类型的所有子对象; 参数作用和上一个类同

# Qlabel组件统一改背景颜色

# 筛选出win_root里面的Qlabel组件子对象,遍历的所有筛选出来的子对象,进行修改
for sub_widget in win_root.findchildren(Qlabel):
	sub_widget.setStyleSheet("background-color: pink;")

2. 应用场景

🔰涉及到Qt对象内存管理机制;
🔰如果一个组件, 没有任何父组件, 那么就会被当成顶层组件(窗口);
🔰如果想要一个组件被包含在另一个控件内部,就需要设置父子关系;

win_root = Qwidget()

label1 = Qlabel()
label1.setParent(win_root)
等价于
label1 = Qlabel(win_root)

(三) 信号处理

1. 信号与槽机制

1) 基本概念

🔰信号与槽是Qt中的核心机制,主要作用在于对象之间进行通讯。
🔰信号:当一个组件的状态发生改变时,向外界发出的信号。
🔰槽:一个执行某些操作的函数 / 方法。
🔰所有继承自QWidget的组件都支持“信号于槽”的机制。

2) 基本使用介绍

🔰组件内置一些信号,也可以自定义;
🔰不同组件内置额槽函数;自定义的函数 / 方法也是槽;

连接方式及特性

🔰连接方式:object.信号.connect(槽函数)
🔰一个信号可以连接多个槽函数;
🔰一个信号也可以连接多个槽函数;
🔰信号的参数可以是任何Python类型;
🔰一个槽可以监听多个信号;

2. API

🔰widget.信号.connect(槽):连接信号与槽;

信号

🔰objectNameChanged(objectName): 对象名称发生改变时触发此信号;

# 对象.objectNameChanged.connect(槽)
obj.objectNameChanged.connect(obj_name_cao)

🔰destroyed(obj): 对象被销毁时,触发此信号;

# 对象.destroyed.connect(槽)
obj.destroyed.connect(destroy_cao)

del obj  # 释放对象 / 销毁对象

🔰windowTitleChanged(obj):当窗口标题改变时,触发该信号;

window.windowTitleChanged.connect(cao)

🔰windowIconChanged(obj):当窗口图标改变时,触发该信号;

window.windowIconChanged.connect(cao)

🔰obj.disconnect(): 取消连接信号于槽;obj: 可以是组件,也可以是信号;

obj.destroyed.disconnect()

🔰widget.blockSignals(bool): 临时阻止指定组件所有的信号于槽的连接;

obj.blockSignals(True)   # 阻断连接
obj.blockSignals(False)  # 回复连接

🔰widget.signalsBlocked(): 信号是否被阻止;

obj.signalsBlocked() # 若结果是True,表示断开连接

🔰widget.receivers("信号"): 返回连接到信号的接收器数量;

obj.receivers(obj.destroyed)

3. 应用场景

🔰监听信号,响应用户行为;


(四) 类型判定

1. API

🔰isWidgetType(): 判定是否为组件;

obj.isWidgetType()  # 若结果为True,表示是组件

🔰inherits(父类): 判定是否继承于某一个父类;

obj.inherits(“QWidget”)  # 若结果为True,表示该对象继承自QWidget

2. 应用场景

🔰过滤筛选组件;


(五) 对象删除

🔰obj.deleteLater(): 删除一个对象时,也会解除它与父对象之间的关系;
🔰deleteLater() 并没有将对象立即销毁,而是向主消息循环发送一个event,下一次主消息循环收到这个event之后才会销毁对象。这样做的好处是可以在这些延迟删除的时间内完成一些操作,坏处就是内存释放会不及时。
🔰应用场景:想要移除某个对象的时候使用;


(六) 定时器

API

🔰startTimer(ms, Qt.TimerType): 开启一个定时器;
会有一个返回值timer_id;
timer_id 是定时器的唯一标识;

🔰Qt.TimerType参数:

  1. Qt.PreciseTimer精确定时器:尽可能保持毫秒准确;
  2. Qt.CoarseTimer粗定时器:5%的误差间隔;
  3. Qt.VeryCoarseTimer很粗的定时器: 只能到秒级;

🔰killTimer(timer_id):根据定时器id,杀死定时器;
🔰timerEvent():定时器执行事件;

🎀简易计时器案例:

# 0. 导入需要的包和模块
from PyQt5.QtWidgets import *
import sys

class MyLabel(QLabel):
   def __init__(self, *args, **kwargs):
       super(MyLabel, self).__init__(*args, **kwargs)
       self.move(100, 100)
       self.setStyleSheet("font-size: 22px;")

   def setSec(self, sec):
       self.setText(str(sec))

   def startMyTimer(self, ms):
       self.timer_id = self.startTimer(ms)

   def timerEvent(self, *args, **kwargs):
       # 获取当前的标签内容
       current_sec = int(self.text())
       current_sec -= 1
       self.setText(str(current_sec))
       if current_sec == 0:
           self.killTimer(self.timer_id)

# 1. 创建一个应用程序对象
app = QApplication(sys.argv)

# 2. 控件的操作
# 2.1 创建控件(创建窗口)
window = QWidget()
# 2.2 设置控件(窗口属性设置)
window.setWindowTitle("QObject定时器的使用")
window.resize(500, 500)

# 设置内部控件
label = MyLabel(window)
# 计时时间
label.setSec(5)
# 计时间隔
label.startMyTimer(500)

# 2.3 展示控件
window.show()
# 3. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())


四. Qwidget

🔰所有的可视组件的基类;
🔰是一个最简单的空白组件;
🔰组件是用户界面的最小元素。可接受各种事件;绘制在桌面上,展示给用户看;
🔰每个组件都是矩形的,它们按Z轴顺序排序;
🔰组件由其父组件和前面的组件剪切;
🔰没有父组件的组件,称之为窗口。一般会被包装一个框架;可以通过某些设置更改;

(一) 功能作用

1. 大小位置的获取

API解析
label.x()获取相对于父组件的x位置,包含窗口框架
顶层组件则相对于桌面的x位置
label.y()获取相对于父组件的y位置
顶层组件则相对于桌面的y位置
label.pos()x与y的组合
label.width()获取组件的宽度,不包含任何窗口框架
label.height()获取组件的高度,不包含任何窗口框架
label.size()width和height的组合
label.geometry()获取用户区域相对于父控件的位置和尺寸大小
label.rect()0, 0, width, height 的组合
label.frameSize()获取框架大小
label.frameGeometry()获取框架位置和大小

2. 大小位置的设置

API解析
label.move(x, y)设置组件相对于父组件的位置
顶层组件则相对于桌面的位置
label.resize(width, height)设置组件的宽和高,不包括窗口框架
label.setGeometry(x, y, width, height)设置组件的位置和大小
label.adjustSize()根据内容自适应大小
label.setFixedSize(width, height)设置固定大小

3. 最大和最小大小的获取

API解析
label.minimumWidth()获取最小大小的宽度
label.minimumHeight()获取最小大小的高度
label.minimumSize()获取最小大小的宽度和高度
label.maximumWidth()获取最大大小的宽度
label.maximumHeight()获取最大大小的高度
label.maximumSize()获取最大大小的宽度和高度

4. 最大和最小大小的设置

API解析
label.setMaximumWidth(MaxWidth)设置最大大小的宽度
label.setMaximumHeight(MaxHeight)设置最大大小的高度
label.setMaximumSize(MaxWidth, MaxHeight)设置最大大小的宽度和高度
label.setMinimumWidth(MinWidth)设置最小大小的宽度
label.setMinimumHeight(MinHeight)设置最小大小的高度
label.setMinimumSize(MinWidth, MinHeight)设置最小大小的宽度和高度

5. 内容边距

🔰调整组件内容边距,使得显示更好看;

API解析
label.setCOntentsMargins(左,上,右,下)设置内容边距
label.getContentsMargins()获取内容边距
label.contentsRect()获取内容边距

6. 鼠标相关操作

1)设置鼠标形状

🔰label.setCursor(参数)该API的参数如下:

参数显示效果
Qt.ArrowCursor
Qt.UpArrowCursor
Qt.CrossCursor
Qt.IBeamCursor
Qt.WaitCursor
Qt.BusyCursor
Qt.ForbiddenCursor
Qt.PointingHandCursor
Qt.WhatsThisCursor
Qt.SizeVerCursor
Qt.SizeHorCursor
Qt.SizeBDiagCursor
Qt.SizeAllCursor
Qt.SplitHCursor
Qt.SplitVCursor
Qt.OpenHandCursor
Qt.ClosedHandCursor
Qt.BlankCursor
QCursor对象自定义鼠标形状
window.unsetCursor()重置鼠标形状
window.cursor()获取鼠标

自定义鼠标

pixmap = QPixmap("qq.jpg")  # 图片对象
new_pixmap = pixmap.scaled(50, 50)  # 图片大小
cursor = QCursor(new_pixmap, 0, 0)  # 鼠标对象,及作用点坐标位置
window.setCursor(cursor)

2)鼠标跟踪

🔰window.hasMouseTracking():判定是否设置了鼠标跟踪;
🔰window.setMouseTracking(True):设置鼠标是否跟踪;
🔰所谓的鼠标跟踪,其实就是设置检测鼠标移动事件的条件;
🔰不跟踪:鼠标移动时,必须处于按下状态,才会触发mouseMoveEvent事件;
🔰跟踪:鼠标移动时,不处于按下状态,也会触发mouseMoveEvent事件;

7. 事件

🔰当一个组件被触发了一个特定的行为时,就会调用特定的方法,来将事件传递给开发人员,方便处理;
🔰重写这些事件方法,就可以监听相关的信息;

1)监听显示和关闭事件

API解析
def showEvent(self, QShowEvent):该事件在组件显示时触发
def closeEvent(self, QCloseEvent):该事件在组件关闭时触发

2)监听移动事件

API解析
def moveEvent(self, QMoveEvent):该事件在组件移动时触发

3)监听调整大小事件

API解析
def resizeEvent(self, QResizeEvent):该事件在组件大小被调整时触发

4)监听鼠标事件

API解析
def enterEvent(self, QEvent):该事件在鼠标进入组件范围时触发
def leaveEvent(self, QEvent):该事件在鼠标离开组件范围时触发
def mousePressEvent(self, QMouseEvent):该事件在鼠标按下时触发
def mouseReleaseEvent(self, QMouseEvent):该事件在鼠标释放时触发
def mouseDoubleClickEvent(self, QMouseEvent):该事件在鼠标双击时触发
def mouseMoveEvent(self, QMouseEvent):该事件在鼠标按下后移动时触发
def mouseMoveEvent(self, QMouseEvent):
___self.setMouseTracking(True)追踪设置
追踪设置后,没有按下的移动也能触发

5)监听键盘事件

API解析
def keyPressEvent(self, QKeyEvent):该事件在键盘按下时触发
def keyReleaseEvent(self, QKeyEvent):该事件在键盘释放时触发

🔰修饰键:

  1. Qt.NoModifier:没有修饰键;
  2. Qt.ShiftModifier:Shift 键被按下;
  3. Qt.ControlModifier:Ctrl 键被按下;
  4. Qt.AltModifier:Alt 键被按下;
    多个修饰键之间使用或运算;

🔰普通键:Qt.Key_xxx

🔰实例:创建一个窗口,用户区支持拖拽。鼠标点击了用户区拖拽也可以移动窗口;

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *

class Window(QWidget):
   def __init__(self):
       super().__init__()
       self.setWindowTitle("用户区鼠标拖拽窗口")
       self.resize(500, 500)

   # 鼠标按下时,触

开源分享基于Python+OpenCV+PyQt5车牌识别(GUI界面)

亲测无错:基于Python+OpenCV+PyQt5车牌识别(GUI界面)绝对可以用的!!!!!

基于Python+OpenCV+PyQt5车牌识别(GUI界面)



参考文档

以上是关于Python界面设计——GUI编程之PyQt5的主要内容,如果未能解决你的问题,请参考以下文章

Java之GUI编程

Python GUI编程之WxPython

java之 22天 GUI 图形界面编程

Python编程基础21:GUI编程

Python GUI编程(Tkinter) windows界面开发

java之 22天 GUI 图形界面编程