要对我们项目的功能进行封装,做一个GUI界面

开始学图形界面,从最热门的pyqt5学起~~

学习大神的视频做得学习笔记

学习视频地址

Python Qt 图形界面编程 - 华为大叔7天带你入门 - PySide2 PyQt5 PyQt PySide

开发环境

  • pycharm
  • python+PyQt5库
  • qt creator

下载QT creator

下载QT的详细教程:下载QT的详细教程

下载QT相关内容的链接集合:下载QT相关内容的链接集合:
//即下载QT creator

下载PyQt5库

  1. 关于PyQt
    在这里插入图片描述
  2. 关于PyQt和PySide2
    PySide2、PyQt5 都是基于著名的 Qt 库。

Qt库里面有非常强大的图形界面开发库,但是Qt库是C++语言开发的,PySide2、PyQt5可以让我们通过Python语言使用Qt。

PySide2、PyQt5 这两者有什么区别呢?

PySide2 是Qt的 亲儿子

PyQt5 是Qt还没有亲儿子之前的收的义子 (Riverbank Computing这个公司开发的)。

那为什么 PyQt5 这个义子 反而比 PySide2 这个亲儿子更出名呢?

原因很简单:PySide2 这亲儿子最近(2018年7月)才出生。

但是亲儿子毕竟是亲儿子,Qt准备大力培养,PySide2 或许更有前途。

已经在使用 PyQt5 的朋友不要皱眉, 两个库的使用 对程序员来说,差别很小:它们的调用接口几乎一模一样。

如果你的程序是PyQt5开发的,通常只要略作修改,比如把导入的名字从 PyQt5 换成 PySide2 就行了。反之亦然。

命令行安装PyQt5

命令行中直接执行

pip install pyqt5-tools

Qt简单界面学习

创建一个简单的界面
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,  QPlainTextEdit

app = QApplication([])

window = QMainWindow()
window.resize(500, 400)
window.move(300, 310)
window.setWindowTitle('薪资统计')

textEdit = QPlainTextEdit(window)
textEdit.setPlaceholderText("请输入薪资表")
textEdit.move(10,25)
textEdit.resize(300,350)

button = QPushButton('统计', window)
button.move(380,80)

window.show()

app.exec_()

运行结果
在这里插入图片描述

QApplication

app = QApplication([])

QApplication 提供了整个图形界面程序的底层管理功能,比如:

初始化、程序入口参数的处理,用户事件(对界面的点击、输入、拖拽)分发给各个对应的控件,等等…

既然QApplication要做如此重要的初始化操作,所以,我们必须在任何界面控件对象创建前,先创建它。

QMainWindow(主窗口)、QPlainTextEdit(文本框)、QPushButton(按钮)

window = QMainWindow()
window.resize(500, 400)//决定它的大小宽度500 高度400
window.move(300, 310)// 控制主窗口出现在显示器屏幕的什么位置 300决定宽 310决定高 距离屏幕右上角的距离
window.setWindowTitle('薪资统计')//窗口的标题
textEdit = QPlainTextEdit(window)//创建在window内
textEdit.setPlaceholderText("请输入薪资表")//提示文本
textEdit.move(10,25)//相对于父窗口的位置 除了标题框的位置
textEdit.resize(300,350)//设置文本框的大小
button = QPushButton('统计', window)//按钮标签以及父窗口
button.move(380,80)/相对于父窗口的位置 除了标题框的位置

QMainWindow、QPlainTextEdit、QPushButton 是3个控件类,分别对应界面的主窗口、文本框、按钮

他们都是控件基类对象QWidget的子类。

要在界面上 创建一个控件 ,就需要在程序代码中 创建 这个 控件对应类 的一个 实例对象。

window.show()//执行这个方法 窗口才能出来 表示要展示在界面上
app.exec_()//防止展示window.show()一闪而过就没了 等待用户的输入 这个程序是一个死循环 
界面动作处理 (signal 和 slot)

在 Qt 系统中, 当界面上一个控件被操作时,比如 被点击、被输入文本、被鼠标拖拽等, 就会发出 信号 ,英文叫 signal。就是表明一个事件(比如被点击、被输入文本)发生了。

我们可以预先在代码中指定 处理这个 signal 的函数,这个处理 signal 的函数 叫做 slot 。

定义一个函数

def handleCalc():
    //print('统计按钮被点击了')
     info = textEdit.toPlainText()

指定如果发生了button 按钮被点击的事情,需要让 handleCalc 来处理,像这样
加载按钮处

button = QPushButton('统计', window)
button.move(380,80)
button.clicked.connect(handleCalc)
//让handleCalc来处理button被点击的操作
//把button被点击(clicked)的信号(signal),连接(connect)到了handleCalc这样的一个slot上

完整的代码定义

def handleCalc():
    info = textEdit.toPlainText()

    # 薪资20000 以上 和 以下 的人员名单
    salary_above_20k = ''
    salary_below_20k = ''
    for line in info.splitlines():
        if not line.strip():
            continue
        parts = line.split(' ')
        # 去掉列表中的空字符串内容
        parts = [p for p in parts if p]
        name,salary,age = parts
        if int(salary) >= 20000:
            salary_above_20k += name + '\n'
        else:
            salary_below_20k += name + '\n'

    QMessageBox.about(window,
                '统计结果',
                f'''薪资20000 以上的有:\n{salary_above_20k}
                \n薪资20000 以下的有:\n{salary_below_20k}'''
                )

运行结果
在这里插入图片描述

封装到类中
from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton,  QPlainTextEdit,QMessageBox

class Stats():
    def __init__(self):
        self.window = QMainWindow()
        self.window.resize(500, 400)
        self.window.move(300, 300)
        self.window.setWindowTitle('薪资统计')

        self.textEdit = QPlainTextEdit(self.window)
        self.textEdit.setPlaceholderText("请输入薪资表")
        self.textEdit.move(10, 25)
        self.textEdit.resize(300, 350)

        self.button = QPushButton('统计', self.window)
        self.button.move(380, 80)

        self.button.clicked.connect(self.handleCalc)


    def handleCalc(self):
        info = self.textEdit.toPlainText()

        # 薪资20000 以上 和 以下 的人员名单
        salary_above_20k = ''
        salary_below_20k = ''
        for line in info.splitlines():
            if not line.strip():
                continue
            parts = line.split(' ')
            # 去掉列表中的空字符串内容
            parts = [p for p in parts if p]
            name,salary,age = parts
            if int(salary) >= 20000:
                salary_above_20k += name + '\n'
            else:
                salary_below_20k += name + '\n'

        QMessageBox.about(self.window,
                    '统计结果',
                    f'''薪资20000 以上的有:\n{salary_above_20k}
                    \n薪资20000 以下的有:\n{salary_below_20k}'''
                    )

app = QApplication([])
stats = Stats()
stats.window.show()
app.exec_()

测试数据

薛蟠 4560 25
薛蝌 4460 25
薛宝钗 35776 23
薛宝琴 14346 18
王夫人 43360 45
王熙凤 24460 25
王子腾 55660 45
王仁 15034 65
尤二姐 5324 24
贾芹 5663 25
贾兰 13443 35
贾芸 4522 25
尤三姐 5905 22
贾珍 54603 35

测试结果
在这里插入图片描述

打开qt designer

路径
在下载了PySide2 就会有qt designer

C:\Users\phl\AppData\Local\Programs\Python\Python38\Lib\site-packages\PySide2
动态加载UI文件

前提:现在我有一个GUI界面设计.ui的文件与py代码在同一目录下

  • PySide2:
from PySide2.QtWidgets import QApplication, QMessageBox
from PySide2.QtUiTools import QUiLoader
from PySide2.QtCore import QFile

 def __init__(self):

        # 从文件中加载UI定义
        qfile_stats = QFile("GUI界面设计.ui")
        qfile_stats.open(QFile.ReadOnly)
        qfile_stats.close()

        # 从 UI 定义中动态 创建一个相应的窗口对象
        # 注意:里面的控件对象也成为窗口对象的属性了
        # 比如 self.ui.button , self.ui.textEdit
        self.ui = QUiLoader().load(qfile_stats)
  • PyQt5:
    main.ui是在同一目录层级下
from PyQt5 import uic

class Stats:

    def __init__(self):
        # 从文件中加载UI定义
        self.ui = uic.loadUi("GUI界面设计.ui")

完整代码

# from PySide2.QtWidgets import QApplication, QMessageBox
# from PySide2.QtUiTools import QUiLoader
# from PySide2.QtCore import QFile
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,  QPlainTextEdit, QMessageBox
from PyQt5 import uic

class Stats:

    def __init__(self):

        # 从文件中加载UI定义
        # qfile_stats = QFile("GUI界面设计.ui")
        # qfile_stats.open(QFile.ReadOnly)
        # qfile_stats.close()

        # 从 UI 定义中动态 创建一个相应的窗口对象
        # 注意:里面的控件对象也成为窗口对象的属性了
        # 比如 self.ui.button , self.ui.textEdit
        # self.ui = QUiLoader().load(qfile_stats)
        self.ui = uic.loadUi("GUI界面设计.ui")

        self.ui.button.clicked.connect(self.handleCalc)//注意修改的地方 原先没有ui button一定要是ui中对象名

    def handleCalc(self):
        info = self.ui.textEdit.toPlainText()
        //textEdit也要是ui中的对象名

        salary_above_20k = ''
        salary_below_20k = ''
        for line in info.splitlines():
            if not line.strip():
                continue
            parts = line.split(' ')

            parts = [p for p in parts if p]
            name,salary,age = parts
            if int(salary) >= 20000:
                salary_above_20k += name + '\n'
            else:
                salary_below_20k += name + '\n'

        QMessageBox.about(self.ui,//同样原先显示时是self.window
                          '统计结果',
                          f'''薪资20000 以上的有:\n{salary_above_20k}
                            \n薪资20000 以下的有:\n{salary_below_20k}'''
                          )

app = QApplication([])
stats = Stats()
stats.ui.show()//原先是stats现在是stats.ui
app.exec_()
转化UI文件为Python代码
  • 安装的是PyQt5
pyuic5 main.ui > ui_main.py
  • 安装的是PySide2
pyside2-uic main.ui > ui_main.py

然后在你的代码文件中这样使用定义界面的类

import sys
from PyQt5 import QtWidgets, uic

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

from ui_main import Ui_Form
//ui_main是我转化过来的py文件 Ui_Form转化的类型 我转化的是Ui_Form 可以是Ui_MainWindow

class MainWindow(QtWidgets.QMainWindow, Ui_Form):
    def __init__(self, *args, obj=None, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

app = QtWidgets.QApplication(sys.argv)

window = MainWindow()
window.show()
app.exec()
界面布局 Layout

使得框体随着窗体变化而变化

  1. QHBoxLayout 水平布局
    QHBoxLayout 把控件从左到右 水平横着摆放,如下所示
    在这里插入图片描述
  2. QVBoxLayout 垂直布局
    QHBoxLayout 把控件从上到下竖着摆放,如下所示
    在这里插入图片描述
  3. QGridLayout 表格布局
    QGridLayout 把多个控件 格子状摆放,有的控件可以 占据多个格子,如下所示
    在这里插入图片描述
  4. QFormLayout 表单布局
    QFormLayout 表单就像一个只有两列的表格,非常适合填写注册表单这种类型的界面,如下所示在这里插入图片描述
    直接调整布局的方法
    在这里插入图片描述
    选中几部分 布局 > 水平布局就可 慢慢调整使得整体是某个布局 使得窗体可以整体变动
    在这里插入图片描述
    如果我们选择的主窗口是MainWindow类型,要给MainWindow整体设定Layout,必须 先添加一个控件到 centralwidget 下面 ,如下
    在这里插入图片描述
    然后才能右键点击 MainWindow,选择布局,如下
    在这里插入图片描述
调整空间位置和大小

情况1:按钮控件过大
效果图 //将文本框与按钮垂直布局
//但是又不希望按钮控件那么大 所以需要调整空间位置和大小
在这里插入图片描述

  1. 将按钮的水平策略从Minimum改成Fixed
    在这里插入图片描述
    效果图
    在这里插入图片描述
  2. 要将按钮居中的话
    先拖放一个水平布局的layout布局
    然后把按钮拖进layout布局中
    在这里插入图片描述
    情况2:如何让三个水平布局的功能 有大有小呢?
    在这里插入图片描述

调整“消息头”的水平伸展数据为2 使得“消息头”为其他两个按钮的两倍大小
//如果调整成其他大小的时候 米有那么明显 因为“+””-“两个按钮也有自己的最小的大小
//当放大窗体时“消息头”就会随之变大 而“+””-“不会变化
在这里插入图片描述
情况3:调整控件上下间距

要调整控件上下间距,可以给控件添加layout,然后通过设定layout的上下的padding 和 margin 来调整间距。

希望调整”消息体“下的文本框与左边的文本框一样大
在这里插入图片描述
创建一个水平布局的layout 将”消息体“放入其中
在这里插入图片描述
调整上图的数据 👆 就可以调整”消息体“的大小了

效果图👇
在这里插入图片描述
情况4:调整控件的左右间距

可以通过添加 horizontal spacer 进行控制,也可以通过layout的左右margin
在这里插入图片描述
使用控件:
在这里插入图片描述
调整大小:
在这里插入图片描述

界面布局步骤建议

对界面控件进行布局,按照如下步骤操作

  1. 先不使用任何Layout,把所有控件 按位置 摆放在界面上

  2. 然后先从 最内层开始 进行控件的 Layout 设定

  3. 逐步拓展到外层 进行控件的 Layout设定

  4. 最后调整 layout中控件的大小比例, 优先使用 Layout的 layoutStrentch 属性来控制

  5. 控制控件之间的间隙,用空间Spacers
    在这里插入图片描述
    !!注意最后面一定要选择MainWindow的布局修改,否则无法实现自适应
    在这里插入图片描述

发布程序

首先下载pyinstaller

pip install pyinstaller

例如我现在要发行static.py

# from PySide2.QtWidgets import QApplication, QMessageBox
# from PySide2.QtUiTools import QUiLoader
# from PySide2.QtCore import QFile
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,  QPlainTextEdit, QMessageBox
from PyQt5 import uic

class Stats:

    def __init__(self):

        # 从文件中加载UI定义
        # qfile_stats = QFile("GUI界面设计.ui")
        # qfile_stats.open(QFile.ReadOnly)
        # qfile_stats.close()

        # 从 UI 定义中动态 创建一个相应的窗口对象
        # 注意:里面的控件对象也成为窗口对象的属性了
        # 比如 self.ui.button , self.ui.textEdit
        # self.ui = QUiLoader().load(qfile_stats)
        self.ui = uic.loadUi("GUI界面设计.ui")

        self.ui.button.clicked.connect(self.handleCalc)

    def handleCalc(self):
        info = self.ui.textEdit.toPlainText()

        salary_above_20k = ''
        salary_below_20k = ''
        for line in info.splitlines():
            if not line.strip():
                continue
            parts = line.split(' ')

            parts = [p for p in parts if p]
            name,salary,age = parts
            if int(salary) >= 20000:
                salary_above_20k += name + '\n'
            else:
                salary_below_20k += name + '\n'

        QMessageBox.about(self.ui,
                          '统计结果',
                          f'''薪资20000 以上的有:\n{salary_above_20k}
                            \n薪资20000 以下的有:\n{salary_below_20k}'''
                          )

app = QApplication([])
stats = Stats()
stats.ui.show()
app.exec_()

cd到当前目录后 输入命令语句

pyinstaller static.py --noconsole --hidden-import PySide2.QtXml

在这里插入图片描述

这时候项目根目录C:\Users\phl\PycharmProjects\pythonProject1就多出了两个目录
在这里插入图片描述
打开dist\static` 运行static.exe会出错在这里插入图片描述
这时候把程序所需要的ui文件拷贝到打包目录中即可了

因为PyInstaller只能分析出需要哪些代码文件。 而你的程序动态打开的资源文件,比如 图片、excel、ui这些,它是不会帮你打包的。

缺少了GUI界面设计.ui这个文件的加载 将GUI界面设计.ui文件粘贴到dist\static中即可

现在打开运行static.exe就不会出错了
在这里插入图片描述
一个可运行的文件就生成了
C:\Users\phl\PycharmProjects\pythonProject1\dist中的static文件夹进行打包 就可发送给别人使用了
在这里插入图片描述
如何知道是缺少哪一个文件使得程序不能运行呢?

–noconsole 指定不要命令行窗口,否则我们的程序运行的时候,还会多一个黑窗口。 但是我建议大家可以先去掉这个参数,等确定运行成功后,再加上参数重新制作exe。因为这个黑窗口可以显示出程序的报错,这样我们容易找到问题的线索。

–hidden-import PySide2.QtXml 参数是因为这个 QtXml库是动态导入,PyInstaller没法分析出来,需要我们告诉它。

关于动态导入库
在这里插入图片描述
最后,别忘了,把程序所需要的ui文件拷贝到打包目录中。

因为PyInstaller只能分析出需要哪些代码文件。 而你的程序动态打开的资源文件,比如 图片、excel、ui这些,它是不会帮你打包的。 图片、excel、ui需要我们自行导入。

程序图标

主窗口图标
在这里插入图片描述
在这里插入图片描述
我们程序运行的窗口,需要显示自己的图标,这样才更像一个正式的产品。

通过如下代码,我们可以把一个png图片文件作为 程序窗口图标。

from PyQt5.QtGui import QIcon

app = QApplication([])
# 加载 icon
app.setWindowIcon(QIcon('logo.png'))

注意:这些图标png文件,在使用PyInstaller创建可执行程序时,也要拷贝到程序所在目录。否则可执行程序运行后不会显示图标。
//jpg也可以

应用程序图标
在这里插入图片描述
应用程序图标是放在可执行程序里面的资源。

可以在PyInstaller创建可执行程序时,通过参数 --icon=“logo.ico” 指定。

比如

pyinstaller httpclient.py --noconsole --hidden-import PySide2.QtXml --icon="logo.ico"

注意参数一定是存在的ico文件,不能是png等图片文件。

如果你只有png文件,可以通过在线的png转ico文件网站,生成ico,比如下面两个网站
网站一

网站二

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐