python3 pyside6图形库学习笔记及实践(一)

avatar
作者
猴君
阅读量:0

目录

前言

本系列文章为b站PySide6教程以及官方文档的学习笔记

原视频传送门:【已完结】PySide6百炼成真,带你系统性入门Qt

官方文档链接:Qt for Python

基础框架

我们来实现一个最简单的窗口,并借由其代码来初步认识pyside6的结构

from PySide6.QtWidgets import QApplication, QMainWindow  class MyWindow(QMainWindow):     def __init__(self):         super().__init__()  if __name__ =="__main__":     app =QApplication()     window = MyWindow()     window.show()     app.exec() 

首先是导入的QApplicationQMainWindow类,这些类是用于创建 GUI 应用程序的基本类。

然后我们从QMainWindow类继承我们自己的窗口类Mywindow,这个类将用于创建应用程序的主窗口,此时类中只调用了父类的构造函数。

主程序中则创建了QApplicationMyWindow类的实例,QApplication 是一个必需的类,它管理应用程序的控制流和主要设置。

window.show()用于显示MyWindow 实例,这将使窗口可见并允许用户与它进行交互

app.exec()用于启动应用程序的事件循环。事件循环是一个无限循环,它等待用户输入和系统事件,并相应地更新应用程序的状态。

这段代码的运行效果如下

请添加图片描述

基础控件

一般来说一个应用程序的运行逻辑无非是用户输入->用户交互->输出

那么这就涉及到三种最基本的控件:按钮、标签和输入框

想要给窗体添加控件,需要在窗体类的构造函数中添加控件实例

QPushButton

该控件需要从PySide6.QtWidgets导入

from PySide6.QtWidgets import QPushButton btn = QPushButton("Click me", self) 

但是光一个控件肯定不行,我们还需要设置它的一些属性,来满足高级需求

事实上,当我们想了解一个控件有哪些属性,以及这些属性分别有什么功能时,可以在Qt Designer上进行测试

当我们配置好vscode中的扩展插件PYQT Integration后,只需在文件上右键就能快速打开Qt Designer

请添加图片描述

我们只需拖动一个部件到窗体上,即可在右侧窗口查看并调试它的一些属性

请添加图片描述

这里列出几个PushButton常用的属性

属性作用
geometry(几何)坐标位置、尺寸大小
text按钮上显示的文字
toolTip鼠标放在按钮上时显示的提示文字

想要为控件实例设置属性,需要调用set+属性名的方法

如下示例

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton  class MyWindow(QMainWindow):     def __init__(self):         super().__init__()         btn = QPushButton("Click me", self)         btn.setGeometry(100, 100, 200, 50) #设置(x,y)坐标为(100,100),而宽高分别为200和50         btn.setText("new text") #重新设置的文字会覆盖初始化时的文字         btn.setToolTip("tips") 

QLabel

该控件需要从PySide6.QtWidgets导入

from PySide6.QtWidgets import QLable lb = QLable("Hello", self) 

下面是一些常用的标签特有属性

属性作用
text标签上显示的文字
textFormat如PlainText、MarkdownText和RichText形式
alignment文本对齐方式
pixmap显示图片

QLineEdit

该控件需要从PySide6.QtWidgets导入

from PySide6.QtWidgets import QLineEdit input = QLineEdit("框中预留文字", self) 

下面是一些常用的输入框特有属性

属性作用
maxLength最大输入长度
readOnly是否设置为只读模式
placeholderText框中无任何输入时显示的文字
pixmap显示图片

初识QtDesigner

制作一个简单页面

登录框

首先我们需要考虑页面中会出现哪些种控件

一般来说登录页面会需要输入账号密码,所以会需要输入框

而提示以及提交则需要标签和按钮控件

将这些元素拖拽入窗口中,并进行初步的属性设置,我们就能得到一个简易的窗口模板

请添加图片描述

此时按Ctrl+R或者点击窗体>预览,我们就能预览当前窗口的效果

请添加图片描述

请添加图片描述

我们会发现窗口的标题还是默认的,我们可以直接去设置窗体本身的属性

请添加图片描述

当设计完毕后,我们可以将设计文件保存为.ui后缀的文件

请添加图片描述

计算器

同样我们也能拖拉出一个计算器的UI,这些过程能让我们逐渐熟悉QtDesigner的操作

请添加图片描述

编译UI文件

在QtDesigner中设计好了界面UI后,只能对其进行预览

如果想在程序中运行并显示我们设计的UI,则需要进一步将其编译为python源码,即py文件

我们可以之间执行如下指令(在安装pyside6的python环境下)

pyside6-uic xxx.ui -o xxx.py 

或者在vscode中,我们可以利用插件PYQT Integration的功能

右键ui文件,选择PYQT:Compile Form即可

请添加图片描述

使用编译得到的py文件

上一步中,我们通过编译login.ui文件得到了UI_login.py的py源码

窗口文件在一个叫Ui_Form的类中

请添加图片描述

两种方法在其他的程序中调用这个生成的窗口UI

  1. 在需要调用的地方创建一个该对象的实例

    from Ui_login import Ui_Form class MyWindow(QWidget):     def __init__(self):         super().__init__()         self.login = Ui_Form()         self.login.setupUi(self) 

    setupUi为我们生成的UI的类中的函数,参数需要将我们当前的窗体传进去,这里我们直接传self

    需要注意的是我们的MyWindow继承的窗口类型需要与UI文件的一致

  2. 第二种方法则是利用python多继承的特性,即我们的窗口可以继承多个类

    将Ui_Form也作为我们窗口的父类

    from Ui_login import Ui_Form class MyWindow(QWidget,Ui_Form):     def __init__(self):         super().__init__()         self.setupUi(self) 

信号与槽

概念

PYQT界面的交互需要依靠信号与槽,类似于其他图形界面编程中的事件响应

事件响应机制的图形界面会不断地update,来检测页面中是否有什么元素发生了变化

而信号与槽的机制中,只有界面元素发出信号给相应的槽,页面才会进行修改

信号 (Signals)

  • 定义:信号是PySide6(和Qt)中的一个关键概念,是从对象发送的消息,表明发生了某种事件或状态变化。
  • 特点:信号不包含处理逻辑,它们只负责通知事件的发生。

槽 (Slots)

  • 定义:槽是用来接收信号的方法。当与信号相连的特定事件发生时,相应的槽函数会被调用。
  • 特点:槽可以是任何可调用的Python函数或方法。

信号与槽 vs 事件触发响应

事件触发响应

  • 机制:基于事件循环,当用户进行操作(如点击、键入)时,事件被生成并放入事件队列,然后由应用程序逐个处理。
  • 应用:通常用于处理用户输入、窗口变化等。
  • 优点
    • 直观性:事件处理通常更直观,易于理解。
    • 控制性:可以在事件处理中有更多控制,如事件过滤。
  • 缺点
    • 紧耦合:事件处理函数通常与特定控件或场景紧密相关。
    • 处理复杂性:对于复杂的交互,事件处理可能变得复杂和冗长。

信号与槽

  • 机制:基于信号的发送和槽的接收,更侧重于对象间的通信。
  • 应用:适合于不同组件间的通信,例如,一个组件的行为触发另一个组件的反应。
  • 优点
    • 解耦:发信者和接收者不需要知道彼此的存在。
    • 灵活性:可以连接多个槽到一个信号,或将一个槽连接到多个信号。

示例

from PySide6.QtWidgets import QApplication, QPushButton  app = QApplication([])  # 创建一个按钮 button = QPushButton("Click me")  # 定义槽函数 def on_button_clicked():     print("Button clicked!")  # 将按钮的clicked信号连接到槽函数 button.clicked.connect(on_button_clicked)  button.show() app.exec() 

在这个例子中,当按钮被点击时,clicked信号被发出,然后on_button_clicked槽函数被调用。

我们通过.connect将信号与槽连接起来

实践

完善登录框

为了了解我们之前设计的UI中各控件的对象名,我们可以回到QtDesigner中查看

请添加图片描述

例如第一个输入框,它被自动命名为lineEdit,那么我们在代码中就能通过self.lineEdit调用它

from PySide6.QtWidgets import QApplication, QWidget, QLineEdit from Ui_login import Ui_Form class MyWindow(QWidget,Ui_Form):     def __init__(self):         super().__init__()          self.setupUi(self)         self.pushButton.clicked.connect(self.loginFuc)     def loginFuc(self):         username = self.lineEdit.text()         password = self.lineEdit_2.text()         if username =="admin" and password =="123456":             print("登录成功")         else:             print("登录失败") if __name__ =="__main__":     app =QApplication()     window = MyWindow()     window.show()     app.exec() 

在代码中,我们让之前的UI界面有了响应,即用户名和密码输对时会在控制台输出"登录成功",否则输出"登陆失败“

完善计算器

我们来对之前的计算器界面重新布局一下

布局的好处是缩放界面时,控件的位置与大小也能自动的做出相应调整

请添加图片描述

对每一行按钮水平布局后,我们再对整体进行垂直布局

请添加图片描述

此时的控件还没有与窗口的位置形成相对关系,无法对页面缩放做出响应

请添加图片描述

我们将页面整体改为垂直布局,并适当调整最上方输入框的高度

请添加图片描述

此时我们就能得到一个较为整齐的计算器界面

为了后续在代码中更清晰地编写信号与槽的逻辑,我们需要对页面控件重新命名

请添加图片描述

例如.按钮,我们将其命名为pushButton_dot

那么计算器的逻辑中我们没有必要绑定太多槽

一个思路是先利用其他按钮的信号生成算式的字符串,每次调用槽的时候刷新输入框的显示

def addNumber(self,number):     self.lineEdit.clear()     self.expression+=number     self.lineEdit.setText(str(self.expression))  

在代码中,我们新建一个bind()函数来记录绑定关系,然后在初始化函数中一并调用bind即可

这样能保证初始化函数的简洁性

def bind(self):     self.pushButton_0.clicked.connect(lambda:self.addNumber('0'))     self.pushButton_1.clicked.connect(lambda:self.addNumber('1'))       self.pushButton_2.clicked.connect(lambda:self.addNumber('2'))     self.pushButton_3.clicked.connect(lambda:self.addNumber('3'))     self.pushButton_4.clicked.connect(lambda:self.addNumber('4'))     self.pushButton_5.clicked.connect(lambda:self.addNumber('5'))           self.pushButton_6.clicked.connect(lambda:self.addNumber('6'))     self.pushButton_7.clicked.connect(lambda:self.addNumber('7'))     self.pushButton_8.clicked.connect(lambda:self.addNumber('8'))     self.pushButton_9.clicked.connect(lambda:self.addNumber('9'))     self.pushButton_add.clicked.connect(lambda:self.addNumber('+'))     self.pushButton_sub.clicked.connect(lambda:self.addNumber('-'))     self.pushButton_mul.clicked.connect(lambda:self.addNumber('*'))     self.pushButton_div.clicked.connect(lambda:self.addNumber('/'))     self.pushButton_dot.clicked.connect(lambda:self.addNumber('.'))     self.pushButton_enter.clicked.connect(self.count) 

{% note info %}
在 Python 编程语言中,lambda 关键字用于创建匿名函数,这种函数称为 lambda 函数。Lambda 函数可以接受任何数量的参数,但只能有一个表达式。它们通常用于需要函数对象的地方,但又不想在代码中定义完整的函数。Lambda 函数的基本语法如下:

lambda arguments: expression 

{% endnote %}

在绑定信号时如果我们直接写成:

self.pushButton_0.clicked.connect(self.addNumber('0')) 

这样当python解释器读到这一行代码时会立即执行 self.addNumber('0') ,这并不是我们想要的。我们希望的是,每次按钮被点击时,才调用 self.addNumber('0')。我们需要传递一个函数对象给connect

为了解决这个问题,我们使用 lambda 创建了一个匿名函数,这个匿名函数没有参数,并在被调用时执行 self.addNumber('0')。这样,每次按钮被点击时,实际上是调用这个匿名函数,然后这个匿名函数再去调用 self.addNumber('0')

{% note primary %}

使用 lambda 这种方式使得我们可以在不创建额外的命名函数的情况下,传递带有参数的方法作为信号的槽函数。这

{% endnote %}

当最后当点击计算按钮时,借助python中的eval()函数,我们能将生成的字符串变为算式

def count(self):     self.result = eval(self.expression)     self.lineEdit.setText(str(self.result))     self.expression = str(self.result) 

当然我们也可以为计算器加上清空和回退的功能

self.pushButton_clear.clicked.connect(self.clear) self.pushButton_back.clicked.connect(self.back)  ......  def clear(self):     self.lineEdit.clear()     self.expression = ''          def back(self):     self.lineEdit.clear()     self.expression = self.expression[:-1]     self.lineEdit.setText(str(self.expression)) 

最终的效果如下

请添加图片描述

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!