您现在的位置是:首页 >技术交流 >Pyqt5 学习随记网站首页技术交流

Pyqt5 学习随记

xiaoruozhi001 2024-07-23 00:01:02
简介Pyqt5 学习随记

Pyqt5 学习随记

(这篇文章在写在这里甚至算不上是一篇文章,这里只是作为学习pyqt的随手笔记,在快速做完这个pid算法的时候,本人会将这篇文章好好的整理下来整理好发布,在后续还会随着对pyqt的深入学习不断的补充)


主要说明:本文大部分内容来自:

PyQt5保姆级教程从入门到精通:直达
还有纸质书籍:《PyQt从入门到精通》清华大学出版社
(在清华大学出版社中能找到帮助的资料)

补充:还有PyQt5 控件学习(一个一个学习之QLabel) 这个和本文的思路如出一辙


本文主要是在实现PID算法模拟界面中同步学习PyQt

首先发现程序的结构都.py文件之间相互import,像极了c语言中调用的.h文件函数。

首先找到常见的调用结构如下:

import sys
import PID #PTD是自己写的包

from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt5.QtWidgets import QMainWindow, QGridLayout, QApplication
from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QTextCursor
from PyQt5.QtCore import Qt

from pid_ui import Ui_MainWindow # PID_UI是布置好界面以后编译生成的py文件

解决问题和疑问

  • 2. PyQt中的QtCore,QtGui,QtWidgets分别是什么含义,相对应的内容是什么?在这里插入图片描述
  • 3.

摸着石头过河

1.通过对第一个案例的创建(运用了lable控件)在这里插入图片描述
了解到大致的流程 :(需要仔细阅读注释)

import sys
import demo2

from PyQt5.QtWidgets import QApplication,QMainWindow

if __name__ == '__main__':
    # 只有直接运行这个脚本,才会往下执行
    # 别的脚本文件执行,不会调用这个条件句

    # 实例化,传参
    app = QApplication(sys.argv)

    # 创建对象
    mainWindow = QMainWindow()

    # 创建ui,引用demo1文件中的Ui_MainWindow类
    ui = demo2.Ui_MainWindow()
    # 调用Ui_MainWindow类的setupUi,创建初始组件
    ui.setupUi(mainWindow)
    # 创建窗口
    mainWindow.show()
    # 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)
    sys.exit(app.exec_())

  1. 既然我能增加Qt控件,那我怎么通过代码修改里面的内容呢?

根据书中P142页描述,可以在图形化界面的属性栏中直接修改,也可以在编译出来的python代码中通过用QLabel类的setText()方法:

        self.label=QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20,2,10,10))
        self.label.setText(_translate("MainWindow","shabi"))

值得注意的是这里setTex中用到了这样的一个表达式
“_translate(“MainWindow”,“shabi”)”
由此产生问题:_translate(“MainWindow”,“shabi”)是什么用法?
通过代码中的: _translate = QtCore.QCoreApplication.translate 转而分析
QtCore.QCoreApplication.translate是什么用法?

由此可见我们大致能从中看到每一个控件修改的方法应该是在 图形化编程界面编译出来的文件中,调用相关函数进行修改


既然基本的控件(虽然现在只整了QLable)窥见了一点更改的皮毛,那么我们就可以考虑如何将窗口居中。

  1. 如何将窗口居中?
    在这里插入图片描述
import sys
import typing

from PyQt5 import QtCore 
import Ui_study
from PyQt5.QtWidgets  import QApplication, QMainWindow,QDesktopWidget, QWidget

class CenterForm(QMainWindow):
    def __init__(self,parent=None):
        super(CenterForm,self).__init__(parent)
        self.resize(400,400)
    def center(self):
        screen = QDesktopWidget().screenGeometry()
        size=self.geometry()
        newLeft=(screen.width()-size.width())/2
        newTop=(screen.height()-size.height())/2
        self.move(newLeft,newTop)
if __name__=='__main__':
    app=QApplication(sys.argv)
    main=CenterForm()
    main.show()
    sys.exit(app.exec_())
    
class CenterForm1(QMainWindow):
    def __init__(self, parent: QWidget | None = ..., flags: WindowFlags | WindowType = ...) -> None:
        super().__init__(parent, flags)

写完这个程序我们可以看到,主要将窗口的初始化定义主要是在继承了QMainWindow类的函数中,自定义函数中__init__()初始化函数中进行的初始化。
这里的self在整个class中都是代表自身的意思,这里产生下面几个问题:

  1. init()函数的定义
    为什么vscode的__inital__函数初始化出来的结构是这样的?里面参数都代表了什么?
    在这里插入图片描述2. __inital__函数中 super()的解析是什么?
    super(CenterForm,self).init(parent)

运行这个程序你会看到:
在这里插入图片描述
通过运行结果中不难看出,我们确实实现了将窗口剧中,但是会发现我们之前定义QLable 内容:”xiaoruozhi“不见了,我们需要通对比来发现这种情况的原因:
在这里插入图片描述
我们可以从中看到,这一段中将我们引入编译好的文件,主要是引用到了编译环境继承了 object的类
class MainWindow(object),并且

# 创建ui,引用demo1文件中的Ui_MainWindow类
    ui = demo2.Ui_MainWindow()
    # 调用Ui_MainWindow类的setupUi,创建初始组件
    ui.setupUi(mainWindow)

调用Ui_MainWindow,将其中的内容实例化,通过ui.setupui来实例化,并且通过.setup()的方法来显示ui
我们将不显示”xiaoruozhi“的程序添加上图语句,会得到下面的的结果:
在这里插入图片描述
我们能看到这样我们所定义的空间大致就能出来了


到此我们学会了主要窗口的布局,屏幕中心的位置,ui界面的布局(虽然只有一个Lable),下面我们需要了解我们各种控件是如何和我之间交互的。

我们先看看我们理想中需要构建的ui界面是长什么样子的,都需要用到哪些控件:
在这里插入图片描述我们可以看到在这个ui中,我们使用到了下拉框,按键button,滑动条,文本键入框,两个图像显示
需要用到的交互有:下拉框可以选择下拉的PID算法的模式,按键按下以后通过调用计算实现PID算法图像的显示,两个图像显示框可以用来显示分别两个算法的拟合曲线,拖动滑动条,可以改变Kp,Ki,Kd的值,旁边的 数显示框可以相应的变换对应的数值,同时在数显框中输入想要的参数也能给到三个参数的值。


在了解了我们的需求之后,我们从简单的交互开始做起,分别学相应的控件应该如何实现相应的功能


概念:信号与槽:

信号(signal)与槽(slot)是Qt的核心机制,由于PyQt忠实的继承了Qt的所有特性,所有信号与槽也是PyQt的核心机制。

信号:是由对象或控件发射出去的消息。可以理解为按钮的单击事件。

当单击按钮时,按钮就会向外部发送单击的消息,这些发送出去的信号需要一些代码来拦截,这些代码就是槽

槽本质上是一个函数或者方法,信号可以理解为事件,槽可以理解为事件函数

信号与槽的设置:就是需要将信号和槽绑定

一个信号可以和多个槽绑定,一个槽可以拦截多个信号。

信号和槽绑定有两种方式,一种是用QtDesigner进行绑定,一种是在代码中进行绑定。

1. Button

参考程序:保姆教程中:

如何退出应用程序
可以通过关闭主窗口,由于整个程序只有一个窗口,关闭主窗口之后,应用程序就会退出,之前在第19节演示过
换个思路,通过代码,在窗口上添加一个pashButton,调用QApplication里面的click()方法,来实现退出应用程序,关闭所有窗口

# 退出应用程序
# 用到了水平布局,引入QHBoxLayout
# 需要一个控件,引入了QWidget
# 需要butoon,引入了QPushButton
import sys
from PyQt5.QtWidgets import QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidget
# 用来添加图标
from PyQt5.QtGui import QIcon


class QuitApplication(QMainWindow):

    # 初始化
    def __init__(self):
        super(QuitApplication,self).__init__()

        # 设计窗口的尺寸
        self.resize(300,120)
        # 设置主窗口的标题
        self.setWindowTitle('退出应用程序')


        # 添加Button
        # 创建全局对象self.button1
        self.button1 = QPushButton('退出应用程序')

        # 发送单击信号,执行对应的方法  (将信息与槽关联)
        self.button1.clicked.connect(self.onClick_Button)

        # 创建水平布局
        layout = QHBoxLayout()
        # 将组件加到水平局部里面
        layout.addWidget(self.button1)

        # 放置一个主框架
        mainFrame = QWidget()
        # 在主框架内添加水平布局
        mainFrame.setLayout(layout)
        # 把主框架放在窗口上
        self.setCentralWidget(mainFrame)

    # 按钮的单击事件的方法(自定义的槽)
    def onClick_Button(self):
        sender = self.sender()
        print(sender.text() + '按钮被按下')
        # 得到实例
        app = QApplication.instance()
        # 退出应用程序
        app.quit()


    # 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':

    # 创建app实例,并传入参数
    app =  QApplication(sys.argv)

    # 设置图标
    app.setWindowIcon(QIcon('images/001.jpg'))

    # 创建对象
    main = QuitApplication()

    # 创建窗口
    main.show()

    # 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)
    sys.exit(app.exec_())

在这个程序中我们看到button的出现是加载在布局layout上的,我们还能看到我们用到button控价需要我们引入QPushButton来实现 ,这和我们想象中的在ui文件编译出来的button是不同的,这就应该表明了除了通过引用ui,我们也可以在配置的py文件中通过增加布局和控件实现相同的效果。

通过查看纸质书中的P152PushButton,我们发现其文件在编译出来的文件中添加:
为登录按钮的clikced信号绑定自定义槽函数

self.pushButton.clicked.connet(self.login)
#为登录按钮的clicked信号绑定自定义槽函数
self.pushbutton_2.clicked.connect(MainWindow.close)
#为退出按钮的clicked信号绑定MainWindow窗口自带的close函数

然后自定义了self.login的函数以此实现了自定义函数的效果

我们也仿照一个做出来:
书上的内容是关于直接在编译的py文件中写,这显然是不符合后期不断调试变更位置方便性考虑的,应该主要使用在文件中调用头文件来显示。
在这里插入图片描述
我们可以清晰的看到通过点击ui中按钮可以实现在输出中打印“hhh”的效果

通过编写这个程序有利于我们了解ui是如何调用的

2.1 Lable

QLabel常用的信号(事件):
1.当鼠标划过QLabel控件时触发:linkHovered

2.当鼠标单击QLabel控件时触发:linkActivated

self.label=QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(30,30,81,41))
self.label.setText("用户名:")
print(self.label.text()) #打印出了lable的文本(获取标签文本)

2.2 LineEdit: 单行文本框

# QLabel控件的基本用法

import sys
# 导入QLabel模块  QVBoxLayout垂直布局  (QHBoxLayout 水平布局)
from PyQt5.QtWidgets import QVBoxLayout,QMainWindow,QApplication,QLabel,QWidget
# 导入调制板,调制QLabel背景色
# 导入显示图片包QPixmap
from PyQt5.QtGui import QPixmap,QPalette
# 导入一些Qt的常量
from PyQt5.QtCore import Qt

# 编写一个类,从QWidget中继承
class QLabelDemo(QWidget):
    def __init__(self):
        super().__init__()
        # 调用初始化UI的一个方法
        self.initUI()

    # 规范代码,初始化UI直接写在一个方法里
    def initUI(self):
        # 创建四个label控件
        label1 = QLabel(self)
        label2 = QLabel(self)
        label3 = QLabel(self)
        label4 = QLabel(self)


        # 给label1设置文本,支持html的标签
        label1.setText("<font color=purpel>这是一个文本标签.</font>")
        # 用调试板自动填充背景
        label1.setAutoFillBackground(True)
        # 创建调试板
        palette = QPalette()
        # 给调试板设置背景色
        palette.setColor(QPalette.Window,Qt.blue)
        # 对label1使用调试板
        label1.setPalette(palette)
        # 让label1居中对齐
        label1.setAlignment(Qt.AlignCenter)


        # 给label2设置<a>标签
        label2.setText("<a href='#'>欢迎使用Python GUI程序</a>")  # 可以在a标签里触发事件或者跳转网页 二者选其一

        # 给label3设置文本居中
        label3.setAlignment(Qt.AlignCenter)
        # 给label3设置提示文本
        label3.setToolTip('这是一个图片标签')
        # 让label3显示图片
        label3.setPixmap(QPixmap("./images/4.jpg"))   # 同级目录写法./images

        # 给label4设置文本内容
        label4.setText("<a href='https://www.baidu.com/'>打开百度</a>")  # setText里面的内容要用双引号,单引号会报错
        # 让label4打开链接
        # 如果设为True,用浏览器打开网页,如果设为False,调用槽函数
        label4.setOpenExternalLinks(True)
        # 让label4的文本右对齐
        label4.setAlignment(Qt.AlignRight)
        # 给label4设置提示文本
        label4.setToolTip('这是一个超链接')

        # 创建一个垂直布局
        vbox = QVBoxLayout()
        # 分别把这四个控件放到这个布局里面           布局函数 addWidget
        vbox.addWidget(label1)
        vbox.addWidget(label2)
        vbox.addWidget(label3)
        vbox.addWidget(label4)

        # 将信号与槽绑定
        label2.linkHovered.connect(self.linkHovered)
        label4.linkActivated.connect(self.linkClicked)

        # 设置布局
        self.setLayout(vbox)
        self.setWindowTitle('QLabel控件演示')
        # 设置标题


    # 槽有两个方法 1.滑过  2.单击
    def linkHovered(self):
        print("当鼠标滑过label2标签时,触发事件")

    def linkClicked(self):
        print("当鼠标单击label4标签时,触发事件")
  # 防止别的脚本调用,只有自己单独运行,才会调用下面代码
if __name__ == '__main__':

    # 创建app实例,并传入参数
    app =  QApplication(sys.argv)

    # 设置图标
    # app.setWindowIcon(QIcon('images/001.jpg'))

    # 创建对象
    main = QLabelDemo()
    # 创建窗口
    main.show()

    # 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)
    sys.exit(app.exec_())

单行文本框的相关的内容:

  1. 显示相关内容
  2. 鼠标划过的时候显示内容,点击的时候显示内容(用到动作)

我们自己也写一个lable的相关内容
但是注意

今天学到Pyqt5 label的linkHovered.connect(self.方法), 发现只有label标签的内容为超级链接的时候,才会触发划过方法,特此记录!(同样actived也是这样的触发形式)


3.ComboBox:下拉组合框

为下拉列表及信号与槽之间的关系:
在.py文件代码中自定义一个showinfo()方法,用来将Comobox下拉列表中选择的项显示在Lable标签中,代码如下:

def showifo(self):
	self.labl_2.setText("您的职位是"+"self.comboBox.currentText()")
#定义职位列表
list=["总经理","人事部经理","财务部经理","部门经理","普通员工"]
self.comboBox.additems(list)
#将ComBox控件的选项更改信号与自定义函数槽相关联
self.comboBox.currentindexChanged.connect(self,showinfo)

4. QSlider 滑块控件

"""
滑块控件
通过滑块左右或者上下拉动来控制数字变化
"""
# 如何通过滑块标签来设置字体的大小

import sys
# QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
from PyQt5.QtCore import *
# QtGui 显示应用程序图标,工具提示和各种鼠标光标。
from PyQt5.QtGui import *
# Qt Widgets模块提供了一组UI元素来创建经典的桌面风格的用户界面。
from PyQt5.QtWidgets import *


class QSliderDemo(QWidget):
    def __init__(self):
        super(QSliderDemo, self).__init__()
        self.initUI()

    def initUI(self):
        # 设置窗口标题
        self.setWindowTitle('滑块控件演示')
        # 设置窗口尺寸
        self.resize(300,300)

        # 创建垂直布局
        layout = QVBoxLayout()

        # 创建label控件
        self.label = QLabel('你好,PyQt5')
        # 让label控件居中显示
        self.label.setAlignment(Qt.AlignCenter)




        # 创建滑块控件,有两种:水平和垂直
        # 创建水平的滑块控件slider
        self.slider = QSlider(Qt.Horizontal)
        # 创建垂直的滑块控件slider1
        self.slider1 =   QSlider(Qt.Vertical)

        # 设置最小值12
        self.slider.setMinimum(12)
        self.slider1.setMinimum(12)
        # 设置最大值
        self.slider.setMaximum(58)
        self.slider1.setMaximum(58)
        # 步长
        self.slider.setSingleStep(3)
        self.slider1.setSingleStep(3)
        # 设置当前值
        self.slider.setValue(18)
        self.slider1.setValue(12)
        # 设置刻度的位置,刻度在下方
        self.slider.setTickPosition(QSlider.TicksBelow)
        # 设置刻度的位置,刻度在左方
        self.slider1.setTickPosition(QSlider.TicksLeft)
        # 设置刻度的间隔
        self.slider.setTickInterval(6)
        self.slider1.setTickInterval(3)

        # 把控件添加到垂直布局里
        layout.addWidget(self.label)
        layout.addWidget(self.slider)
        layout.addWidget(self.slider1)

        #信号槽的绑定
        self.slider.valueChanged.connect(self.valueChange)
        self.slider1.valueChanged.connect(self.valueChange)

        # 应用于垂直布局
        self.setLayout(layout)

    # 槽方法
    def valueChange(self):
        print('当前值:%s' % self.slider.value())
        print('当前值:%s' % self.slider1.value())
        # 获得值
        size = self.slider.value()
        size = self.slider1.value()
        # 设置字体字号,让字号通过值发生变化
        self.label.setFont(QFont('Arial',size))


# 防止别的脚本调用,只有自己单独运行时,才会调用下面代码
if __name__ == '__main__':
    # 创建app实例,并传入参数
    app= QApplication(sys.argv)
    # 创建对象
    main = QSliderDemo()
    # 创建窗口
    main.show()
    # 进入程序的主循环,并通过exit函数,确保主循环安全结束(该释放资源的释放资源)
    sys.exit(app.exec_())

5.

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。