Python可视化模块(PyQt5)的快速入门(一)

PyQt5

通过Python去开发一个可视化界面的工具,需要用到GUI的库。我选择了PyQt5,但是我从未接触过,所以进行一番学习

写在前面,基本是各种查阅资料,各种学。有点问题部分希望大家提出相互交流,共同进步,在此拜谢!
前两天由于电脑被公司的流氓软件劫持了···(再次不细说了,都是泪),所以重装了系统。外加我本人还去秦皇岛玩了一圈嘿嘿。耽搁了一些更新的时间

简单介绍 : PyQt5是基于Qt框架的Python绑定。它使Python开发者能够构建一个桌面程序

  1. 安装PyQt5

    pip install PyQt5

  2. 一段简单的PyQt5代码

    import sys
    from PyQt5.QtWidgets import QApplication, QWidget
    
    app = QApplication(sys.argv)   # 创建应用对象(系统环境初始化)
    window = QWidget()             # 创建窗口
    window.show()                  # 显示窗口
    
    sys.exit(app.exec_())          # 启动事件循环,保持窗口响应,直到用户关闭窗口
    

    在这里

    app = QApplication(sys.argv) # 创建应用对象(系统环境初始化)

    这个是所有PyQt5的第一步

    ​ QApplication,是应用的引擎:

    • 控制整个应用的运行

    • 管理程序的界面事件循环(event loop)

    • 处理窗口控件、键盘、鼠标等事件

    • 管理GUI的资源与状态

      sys.argv:

    • 传递外部参数给应用chengxu
    • 如果给命令行运行程序,可以通过sys.argv接受

    sys.exit(app.exec_()) # 启动事件循环,保持窗口响应,直到用户关闭窗口

    这个是所有GUI程序的主事件循环入口

    app.exec_()

    • 启动事件循环:监听点击、用户输入、相应按钮动作
    • 没有它,窗口就一闪而过了,程序直接推出

    sys.exit_()

    • 将sys.exec_的返回值传给操作系统
    • 告知系统我已退出,有没有问题
  3. 基础控件大全(其实也不是很全)

    控件类型 类名 说明
    标签 QLabel 显示文本或图片
    输入框 QLineEdit 用户输入一行文本
    多行文本框 QTextEdit 输入多行文本
    按钮 QPushButton 点击触发事件
    下拉选择框 QComboBox 选择项
    复选框 QCheckBox 多选项
    单选按钮 QRadioButton 单选项
  4. 信号与槽(事件机制)

    信号:事件发出------按钮被点击

    槽: 事件处理器-----定义的函数

    核心:

    ​ 1.信号发出者不需要知道槽函数是如何实现的,只是负责“广播事件”,槽负责响应事件。(解耦

    ​ 2.信号随时发出,执行看事件的循环机制(异步执行

    一个信号可以连接多个槽函数

    多个信号触发一个槽也行

    举个栗子:

      # 连接按钮的点击信号到槽函数
            self.button.clicked.connect(self.update_label)
      # 这里的self.button.clicked就是信号
      # 这里的self.update_label就可以理解为槽函数,用于响应信号
    

    注意:可以自定义信号与槽

    通过pyqtSignal来创建自定义信号

    from PyQt5.QtCore import QObject, pyqtSignal
    from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget
    import sys
    
    class MyObject(QObject):
        # 创建一个自定义信号
        custom_signal = pyqtSignal(str)
    
        def __init__(self):
            super().__init__()
    
        def trigger_signal(self, message):
            self.custom_signal.emit(message)
    
    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("自定义信号示例")
            self.resize(300, 150)
    
            self.label = QLabel("等待消息...")
            self.button = QPushButton("触发信号")
    
            layout = QVBoxLayout()
            layout.addWidget(self.label)
            layout.addWidget(self.button)
    
            self.setLayout(layout)
    
            # 实例化 MyObject 类
            self.my_object = MyObject()
    
            # 连接自定义信号到槽函数
            self.my_object.custom_signal.connect(self.update_label)
    
            # 按钮点击触发信号
            self.button.clicked.connect(lambda: self.my_object.trigger_signal("自定义信号触发!"))
    
        def update_label(self, message):
            self.label.setText(message)
    
    app = QApplication(sys.argv)
    win = MyWindow()
    win.show()
    sys.exit(app.exec_())
    
  5. 布局管理

    layout = QVBoxLayout()

    创建一个垂直布局管理器

    可以把布局想象成一个空房间,把控件丢进去就会自己整齐排好

    布局类 说明
    QVBoxLayout 垂直布局
    QHBoxLayout 水平布局
    QGridLayout 网格布局
  6. 多线程(重点)

    应用背景:PyQt程序运行时,若需要执行一个耗时操作(读取大文件、联网、图片处理、延时循环等等),并且这些操作是在主线程(GUI线程)进行的,则会产生:

    • 窗口卡顿
    • 无响应提示
    • 界面无法点击/无法关闭

    PyQt有两种线程支持方式:

    • QThread(推荐,支持信号机制)⭐⭐⭐⭐⭐
    • threading.Thread(Python原生线程,与QT不兼容)

    可以理解为:

    主线程:画画的人(维持页面稳定)

    子线程:干活的人(读取、计算、下载)

    形象理解-----------如果你要让画画的人去干活,那画面就卡住了

    import sys
    from PyQt5.QtCore import QThread, pyqtSignal
    from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton
    
    # 创建一个工作线程类
    class MyThread(QThread):
        countChanged = pyqtSignal(int)  # 定义信号,发送整数
    
        def run(self):
            for i in range(1, 11):
                self.sleep(1)  # 模拟耗时任务
                self.countChanged.emit(i)  # 每次发出一个信号
    
    # 主界面
    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("多线程演示")
            self.resize(300, 150)
    
            self.label = QLabel("点击开始计数")
            self.button = QPushButton("开始")
    
            layout = QVBoxLayout()
            layout.addWidget(self.label)
            layout.addWidget(self.button)
            self.setLayout(layout)
    
            # 实例化线程
            self.thread = MyThread()
    
            # 绑定信号与槽函数
            self.thread.countChanged.connect(self.update_label)
            self.button.clicked.connect(self.start_thread)
    
        def update_label(self, value):
            self.label.setText(f"计数:{value}")
    
        def start_thread(self):
            if not self.thread.isRunning():
                self.thread.start()
    
    app = QApplication(sys.argv)
    win = MyWindow()
    win.show()
    sys.exit(app.exec_())
    

    需要注意的是:GUI更新必须在主线程

  7. subprocess

    subprocess是用来让Python调用外部命令或程序的工具,而在PyQt多线程中,使用它,是为了让外部调用不阻塞主界面,配合QThread来异步执行命令行任务。

    能干什么?

    • shell命令
    • 启动外部程序
    • 获取紫禁城的输出、错误信息
    • 向子进程传入输入
    • 控制子进程的超时、管道、环境变量等

    subprocess.run()----比Popen()简单

    import subprocess
    
    result = subprocess.run(["ls"], capture_output=True, text=True)
    print(result.stdout)
    #capture_output=True:自动捕获 stdout 和 stderr
    #text=True:表示返回的是字符串(不是 bytes)
    
    
    subprocess.run(["echo", "Hello, World!"])
    #["echo", "Hello, World!"] 是一个列表,第一个是命令,其余是参数。
    

    subprocess.Popen()-----------高级些(看了基本结构,确实是复杂了些)

    import subprocess
    
    process = subprocess.Popen(
        args,                   # 命令和参数(列表)
        stdin=subprocess.PIPE,  # 向子进程输入数据
        stdout=subprocess.PIPE, # 从子进程获取输出
        stderr=subprocess.PIPE, # 获取子进程的错误输出
        text=True,              # 设置文本模式(返回字符串,而不是字节)
        cwd=None,               # 设置子进程的工作目录
        env=None,               # 设置子进程的环境变量
        bufsize=-1,             # 设置缓冲区大小(通常不用设置)
        universal_newlines=True # 自动处理换行符
    )
    
    

    例子①读取输出

    import subprocess
    
    # 启动子进程,执行命令并获取输出
    process = subprocess.Popen(
        ["ls", "-l"],           # 命令及参数
        stdout=subprocess.PIPE,  # 获取标准输出
        stderr=subprocess.PIPE,  # 获取标准错误输出
        text=True               # 使得输出为字符串
    )
    
    # 从子进程读取输出
    stdout, stderr = process.communicate()
    
    # 打印结果
    print("标准输出:", stdout)
    print("标准错误:", stderr)
    
    

    process.communicate() 会等待子进程结束并返回它的输出结果。它会将标准输出和标准错误捕获并返回。

    stdout 为标准输出,stderr 为错误输出。

    例子②通过stdin向子进程输入数据

    import subprocess
    
    # 启动子进程,执行命令
    process = subprocess.Popen(
        ["python", "-c", "import sys; sys.stdin.read()"],
        stdin=subprocess.PIPE,   # 向子进程发送输入数据
        stdout=subprocess.PIPE,  # 获取标准输出
        text=True
    )
    
    # 向子进程输入数据
    output, _ = process.communicate(input="Hello from subprocess!")
    
    # 输出结果
    print("子进程输出:", output)
    

    例子③实时读取输出(长时间运行的任务)

    import subprocess
    
    # 启动子进程
    process = subprocess.Popen(
        ["ping", "www.baidu.com", "-t"],  # Windows 上持续 ping
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )
    
    # 实时读取输出
    for line in process.stdout:
        print("Ping 输出:", line.strip())
    

    不要忘记 .communicate()

    • Popen 是一个异步操作,执行后不会等待子进程结束。如果你不调用 .communicate(),子进程的输出可能不会被捕获。
posted @ 2025-07-19 22:44  CalvinMax  阅读(167)  评论(0)    收藏  举报