PyQt5基础知识

本文内容总结自王铭东老师的PyQt5快速入门,视频链接为:

【PyQt5 快速入门】 https://www.bilibili.com/video/BV1LT4y1e72X/?p=20&share_source=copy_web&vd_source=7f1982c56a437c7b00c3695687b7086d

前言

PyQt是pyhthon语言的GUI(开发图形用户界面)

安装PyQt

  • 1.安装

​ pip install pyqt5

  • 2.验证

​ 进入python解释器

​ 输入 from PyQt5 import QtWdgets

​ 查看版本 from PyQt5.QtCore import *

​ print(QT_VERSION_STR)

第一个PyQt程序

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QWidget # 引入了PyQt5.QtWidgets模块,这个模块包含了基本的组件。

if __name__ == '__main__':

    app = QApplication(sys.argv) # 每个PyQt5应用都必须创建一个应用对象。sys.argv是一组命令行参数的列表。
    
    # print(sys.argv) # 'd:/python_Develop/pyq_code/demo_1.py' 这里是要执行的代码
    
    w = QWidget() # QWidge控件是一个用户界面的基本控件,它提供了基本的应用构造器。默认情况下,构造器是没有父级的,没有父级的构造器被称为窗口(window)。
    
    w.resize(500, 500) # resize()方法能改变控件的大小,这里的意思是窗口宽250px,高150px。
    
    w.move(300, 300) # move()是修改控件位置的的方法。它把控件放置到屏幕坐标的(300, 300)的位置。注:屏幕坐标系的原点是屏幕的左上角。
    
    w.setWindowTitle('My First PyQt Program') # 窗口添加了一个标题,标题在标题栏展示
    
    w.show() # show()能让控件在桌面上显示出来。控件在内存里创建,之后才能在显示器上显示出来。
    
    sys.exit(app.exec_()) # 程序进入循环等待状态,事件处理器这个时候开始工作。主循环从窗口上接收事件,并把事件传入到派发到应用控件里。
                          # 当调用exit()方法或直接销毁主控件时,主循环就会结束。sys.exit()方法能确保主循环安全退出。外部环境能通知主控件怎么结束。

模块介绍

PyQt中有非常多的功能模块,开发中最常用的功能模块主要有三个:

  • QtCore:包含了核心的非GUI的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime类文件、进程与线程一起使用
  • QtGui:包含了窗口系统、事件处理、2D图像、基本绘画、字体和文字类
  • QtWidgets:包含了一些列创建桌面应用的UI元素

PyQt官网的所有模块,地址:https://www.riverbankcomputing.com/static/Docs/PyQt5/module_index.html#ref-module-index

C++具体实现的API文档,地址:https://doc.qt.io/qt-5/qtwidgets-module.html

基础组件介绍

按钮

按钮对应的控件名称为 QPushButton,位于 PyQt5.QtWidgets 里面 类似按钮还有QRadioButton

# 导入按钮库
from PyQt5.QtWidgets import QPushButton

# 在窗口里面添加名字为“关闭"的按钮控件
btn = QPushButton("关闭") 

# 设置按钮的父亲是当前窗口,等于是添加到窗口中显示
btn.setParent(w)

文本

纯文本控件名称为 QLabel , 位于 PyQt5.QtWidgets 里面

纯文本控件仅仅作为标识显示而已,类似输入内容前的一段标签提示(账号 、密码)

from PyQt5.QtWidgets import QLabel

# 下面创建一个Label,然后调用方法指定父类
label = QLabel("我是文本: ", w)
# 设置父对象
label.setParent(w) #在创建的时候指定了父对象:label = QLabel("我是文本: ", w)

# 显示位置与大小 : x, y , w, h
label.setGeometry(20, 20, 30, 30)

输入框

输入框的控件名称为 QLineEdit, 位于 PyQt5.QtWidgets 里面

from PyQt5.QtWidgets import QLineEdit

# 文本框
edit = QLineEdit(w)
edit.setPlaceholderText("请输入账号")
edit.setGeometry(55, 20, 200, 20)

调整窗口大小

from PyQt5.QtWidgets import QWidget

# 实例化一个窗口
w = QWidget()

# 窗口的大小
w.resize(300, 300)

窗口显示在屏幕的中

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget

# 调整窗口在屏幕中央显示
center_pointer = QDesktopWidget().availableGeometry().center() # 获取当前屏幕可用区域的中心点
x = center_pointer.x() # 中心点的x坐标
y = center_pointer.y()
    
#print(w.frameGeometry()) # 得到当前窗口的左上角坐标、宽、高的PyQt5.QtCore.QRect
#print(w.frameGeometry().getRect()) # 得到当前窗口的左上角坐标、宽、高的元组
old_x, old_y, width, height = w.frameGeometry().getRect() 
w.move(x - width / 2, y - height / 2) 

设置窗口icon

可以下载icon图标网站:https://www.iconfont.cn/collections/index?spm=a313x.7781069.1998910419.3(阿里巴巴)

from PyQt5.QtGui import QIcon
# 设置图标
w.setWindowIcon(QIcon('1.png'))
# PyQt是可以隐藏windows默认的标题栏  现在软件90%都隐藏了,重新设置

布局

在Qt的组件中共有四个布局组件:Vertical Layout水平布局组件、Horizontal Layout垂直布局组件、Grid Layout网格布局组件、Form Layout表单布局组件

在Qt的源码中布局分为四大类:QBoxLayout盒子布局类、QGridLayout网格布局类、QFormLayout表单布局类、QStackedLayout抽屉布局类

前面的代码中都是直接实例化组件的对象,设置属性,而布局开始,在代码中类便被广泛的应用。

盒子布局类案例

盒子布局类又分为两个子类QVBoxLayoutQHBoxLayout 负责垂直和水平布局

垂直布局类的案例

import sys
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton, QGroupBox, QMainWindow
from PyQt5.QtCore import Qt

class MyWindow(QWidget):
    def __init__(self):
        # 调用父类的__init__方法,因为它里面有很多对UI空间的初始化操作
        super().__init__()

        # 设置大小
        self.resize(300, 300)
        # 设置标题
        self.setWindowTitle("垂直布局")

        # 垂直布局
        layout = QVBoxLayout() # 创建了一个布局器

        # 在布局器中增加一个伸缩量,类似于弹簧,里面的参数表示QSpacerItem的个数,默认值为零
        # 下面共添加了四个布局伸缩量,比列为1:1:1:2
        layout.addStretch(1)

        # 按钮1
        btn1 = QPushButton("按钮1")
        # 添加到布局器中
        # layout.addWidget(btn1, Qt.AlignmentFlag.AlignTop)
        layout.addWidget(btn1)
		# 添加伸缩量
        layout.addStretch(1)

        # 按钮2
        btn2 = QPushButton("按钮2")
        # 添加到布局器
        layout.addWidget(btn2)
		# 添加伸缩量
        layout.addStretch(1)

        # 按钮3
        btn3 = QPushButton("按钮3")
        # 添加到布局器
        layout.addWidget(btn3)
		# 添加伸量
        layout.addStretch(2)
		
        # 让当前窗口使用这个布局排列
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    # 创建一个QWidget子类
    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

水平布局类案例

import sys
from PyQt5.QtWidgets import QApplication, QHBoxLayout, QWidget, QPushButton, QMainWindow
from PyQt5.QtCore import Qt

class MyWindow(QWidget):
    def __init__(self):
        # 调用父类的__init__方法,因为它里面有很多对UI空间的初始化操作
        super().__init__()

        # 设置大小
        self.resize(300, 300)
        # 设置标题
        self.setWindowTitle("水平布局")

        # 水平布局
        layout = QHBoxLayout() # 创建了一个布局器

        # 在布局器中增加一个伸缩量,类似于弹簧,里面的参数表示QSpacerItem的个数,默认值为零
        # 下面共添加了四个布局伸缩量,比列为2:1:1:2
        layout.addStretch(2)

        # 按钮1
        btn1 = QPushButton("按钮1")
        # 添加到布局器中
        # layout.addWidget(btn1, Qt.AlignmentFlag.AlignTop)
        layout.addWidget(btn1)
		# 添加伸缩量
        layout.addStretch(1)

        # 按钮2
        btn2 = QPushButton("按钮2")
        # 添加到布局器
        layout.addWidget(btn2)
		# 添加伸缩量
        layout.addStretch(1)

        # 按钮3
        btn3 = QPushButton("按钮3")
        # 添加到布局器
        layout.addWidget(btn3)
		# 添加伸量
        layout.addStretch(2)
		
        # 让当前窗口使用这个布局排列
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    # 创建一个QWidget子类
    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

垂直、水平布局类综合案例

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox, QVBoxLayout, QHBoxLayout, QRadioButton


class MyWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.init_ui() # 把原本放在构造函数内部的布局代码,给分离出来放到init_ui(),保证了代码的清爽  

    def init_ui(self):
        # 最外层的是垂直布局器,内部嵌套两部分:爱好组是垂直布局和性别组水平布局
        container = QVBoxLayout()
		
        # -----创建第1个组,添加多个组件-----
        # hobby 主要是保证他们是一个组。
        hobby_box = QGroupBox("爱好")
        # v_layout 保证三个爱好是垂直摆放
        v_layout = QVBoxLayout()
        btn1 = QRadioButton("抽烟")
        btn2 = QRadioButton("喝酒")
        btn3 = QRadioButton("烫头")
        # 添加到v_layout中
        v_layout.addWidget(btn1)
        v_layout.addWidget(btn2)
        v_layout.addWidget(btn3)
        # 把v_layout添加到hobby_box中
        hobby_box.setLayout(v_layout)

        # -----创建第2个组,添加多个组件-----
        # 性别组
        gender_box = QGroupBox("性别")
        # 性别容器
        h_layout = QHBoxLayout()
        # 性别选项
        btn4 = QRadioButton("男")
        btn5 = QRadioButton("女")
        # 追加到性别容器中
        h_layout.addWidget(btn4)
        h_layout.addWidget(btn5)
        # 添加到 box中
        gender_box.setLayout(h_layout)

        # 把爱好的内容添加到容器中
        container.addWidget(hobby_box)
        # 把性别的内容添加到容器中
        container.addWidget(gender_box)

        # 设置窗口显示的内容是最外层容器  布局器可以嵌套
        self.setLayout(container) 

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

网格布局类案例

网格布局又称为九宫格布局

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit, QGridLayout

class MyWindow(QWidget):

    def __init__(self): # 构造函数
        super().__init__() # 初始化父类的构造函数
        self.init_ui() # 将布局代码分离到一起,保持代码清爽

    def init_ui(self):
        self.setWindowTitle("计算器") # 设置标题

        # 准备数据
        data = {
            0: ["%", "CE", "C", "DEL"],
            1: ["1/x", "x^2", "x^(1/2)", "/"],
            2: ["7", "8", "9", "*"],
            3: ["4", "5", "6", "-"],
            4: ["1", "2", "3", "+"],
            5: ["+/-", "0", ".", "="]
        }

        # 整体垂直布局 相当外部垂直布局内嵌套一个输入框和一个网格布局
        layout = QVBoxLayout() 

        # 输入框
        edit = QLineEdit()
        edit.setPlaceholderText("请输入内容") # 不输入东西时的默认显示
        # 把输入框添加到容器中
        layout.addWidget(edit)

        # 网格布局
        grid = QGridLayout()

        # 循环创建追加进去
        for line_number, line_data in data.items():
            # 此时line_number是第几行,line_data是当前行的数据,例如line_number为0时,line_data为['7', '8', '9', '+', '(']
            for col_number, number in enumerate(line_data):
                # 此时col_number是第几列,number是要显示的符号 例如:col_number为0,number为7 colo_number为1,number为8
                btn = QPushButton(number) # 创建显示number的按钮
                grid.addWidget(btn, line_number, col_number) # 网格布局加入按钮,要制定横纵坐标

        # 把网格布局追加到容器中
        layout.addLayout(grid) # 添加组件是:addWidget 添加布局是:addLayout

        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

表单布局类案例

一般适用于提交数据form表单。比如: 登录,注册类似的场景

import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QVBoxLayout, QFormLayout, QLineEdit, QPushButton, QApplication, QWidget


class MyWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        # 设定当前Widget的宽高(可以拉伸大小)
        # self.resize(300, 200)
        # 禁止改变宽高(不可以拉伸)
        self.setFixedSize(300, 150)

        # 外层容器 外层布局为垂直布局
        container = QVBoxLayout()

        # 表单容器
        form_layout = QFormLayout()

        # 创建1个输入框
        edit = QLineEdit()
        edit.setPlaceholderText("请输入账号")
        form_layout.addRow("账号:", edit)

        # 创建另外1个输入框
        edit2 = QLineEdit()
        edit2.setPlaceholderText("请输入密码")
        form_layout.addRow("密码:", edit2)

        # 将from_layout添加到垂直布局器中
        container.addLayout(form_layout)

        # 按钮
        login_btn = QPushButton("登录")
        login_btn.setFixedSize(100, 30)

        # 把按钮添加到容器中,并且指定它的对齐方式
        container.addWidget(login_btn, alignment=Qt.AlignRight)

        # 设置当前Widget的布局器,从而显示这个布局器中的子控件
        self.setLayout(container)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

抽屉布局类案例

QStackedLayout类提供了多页面切换的布局,一次只能看到一个界面。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QStackedLayout, QLabel

class Window1(QWidget):
    def __init__(self):
        super().__init__()
        QLabel("我是抽屉1要显示的内容", self)
        self.setStyleSheet("background-color:green;") # 设置背景为绿色

class Window2(QWidget):
    def __init__(self):
        super().__init__()
        QLabel("我是抽屉2要显示的内容", self)
        self.setStyleSheet("background-color:red;") # 设置背景为红色

class MyWindow(QWidget):
    def __init__(self, parent=None): 
        super().__init__(parent)
        self.create_stacked_layout() # 创建布局器
        self.init_ui()

    def create_stacked_layout(self):  # 不加self就是局部变量,因为创建完后后面的代码还会用
        # 创建堆叠(抽屉)布局
        self.stacked_layout = QStackedLayout()
        # 创建单独的Widget
        win1 = Window1()
        win2 = Window2()
        # 将创建的2个Widget添加到抽屉布局器中 这两个widget的索引为0, 1  默认显示下标为0的 
        self.stacked_layout.addWidget(win1)
        self.stacked_layout.addWidget(win2)

    def init_ui(self):
        # 设置Widget大小以及固定宽高
        self.setFixedSize(300, 270)

        # 1. 创建整体的布局器
        container = QVBoxLayout()

        # 2. 创建1个要显示具体内容的子Widget 
        widget = QWidget()
        widget.setLayout(self.stacked_layout) # 把上面创建的抽屉布局器,设置为当前布局器
        widget.setStyleSheet("background-color:grey;")

        # 3. 创建2个按钮,用来点击进行切换抽屉布局器中的Widget
        btn_press1 = QPushButton("抽屉1")
        btn_press2 = QPushButton("抽屉2")
        # 给按钮添加事件(即点击后要调用的函数)
        btn_press1.clicked.connect(self.btn_press1_clicked)
        btn_press2.clicked.connect(self.btn_press2_clicked)

        # 4. 将需要显示的空间添加到布局器中
        container.addWidget(widget)
        container.addWidget(btn_press1)
        container.addWidget(btn_press2)

        # 5. 设置当前要显示的Widget,从而能够显示这个布局器中的控件
        self.setLayout(container)

    def btn_press1_clicked(self):
        # 设置抽屉布局器的当前索引值,即可切换显示哪个Widget
        self.stacked_layout.setCurrentIndex(0)

    def btn_press2_clicked(self):
        # 设置抽屉布局器的当前索引值,即可切换显示哪个Widget
        self.stacked_layout.setCurrentIndex(1)

if __name__ == "__main__":
    app = QApplication(sys.argv)

    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

窗口

在Qt中窗口类仅有三个,分别为:QWidget、QMainWindow、QDialog

QWidget类演示

控件和窗口的父类,自由高度(什么都没有),没有划分菜单、工具栏、状态栏、主窗口等区域。

适合于创建纯净的窗口!!

import sys
from PyQt5.QtWidgets import QWidget, QLabel , QApplication

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

    def initUI(self):
        label = QLabel("这是文字~~" )
        label.setStyleSheet("font-size:30px;color:red")
        label.setParent(self)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = mywnd()

    #设置窗口标题
    w.setWindowTitle("qwidget")

    # 展示窗口
    w.show()

    # 程序进行循环等待状态
    app.exec()

QMainWindow类演示

它是QWidget的子类,意味着可以在QWidget上加东西,包含菜单栏、工具栏、状态栏、标题栏等,中间部分则为主窗口区域

import sys
from PyQt5.QtWidgets import QMainWindow, QLabel, QApplication

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        label = QLabel("这是文字~~")
        label.setStyleSheet("font-size:30px;color:red")

        # 调用父类中的menuBar,对菜单栏进行操作 MainWindow是QWidget的子类可以在其基础上进行扩展
        menu = self.menuBar()

        file_menu = menu.addMenu("文件")
        file_menu.addAction("新建")
        file_menu.addAction("打开")
        file_menu.addAction("保存")

        edit_menu = menu.addMenu("编辑")
        edit_menu.addAction("复制")
        edit_menu.addAction("粘贴")
        edit_menu.addAction("剪切")

        # 设置中心内容显示
        self.setCentralWidget(label) # QMainWindow与QWidget不同之处 由于QMainWindow分三个部分,顶部的菜单来,最下面的状态栏和中间的内容区域
       								 # 而QWidget这个区域都是显示内容,故要想让文本正常显示,必须设置到内容区域才能正常显示。

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()
    # 设置窗口标题
    w.setWindowTitle("我是窗口标题....")
    # 展示窗口
    w.show()

    # 程序进行循环等待状态
    app.exec()

QDialog类演示

弹出来的对话窗口的基类

import sys
from PyQt5.QtWidgets import QDialog, QPushButton, QApplication

class MyDialog(QDialog):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        ok_btn = QPushButton("确定", self)
        ok_btn.setGeometry(50, 50, 100, 30)
        
if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyDialog()
    # 设置窗口标题
    w.setWindowTitle("对话框")
    # 展示窗口
    w.show()

    # 程序进行循环等待状态
    app.exec()

信号和槽(超级重点)

信号(signal)

在Qt中可以将信号理解为事件或者状态,例如:按钮点击 、内容发生改变 、窗口的关闭事件 或者是 check选中了的状态。

当程序触发了某种状态或者发生了某种事件,即可发射出来一个信号

槽(slot)

若想捕获这个信号,然后执行相应的逻辑代码,那么就需要使用到 槽 , 槽实际上是一个函数, 当信号发射出来后,会执行与之绑定的槽函数

信号和槽链接

为了能够实现,当点击某个按钮时执行某个逻辑,需要把具体的信号和具体的槽函数绑定到一起.

对象.信号.connect(槽函数)
例如: btn.clicked.connect(self.click_my_btn) btn为按钮对象 clicked为点击信号 click_my_btn为槽函数

信号可以分为Qt自带的和我们自定义两种。

信号和槽的案例一:Qt自带信号

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

class MyWindow(QWidget):
    def __init__(self):
        super().__init__() # 初始化父类
        self.init_ui() 

    def init_ui(self):
        # 更改当前Widge的宽高
        self.resize(500, 300)
        # 创建一个按钮
        btn = QPushButton("点我点我", self)
        # 设置窗口位置、宽高
        btn.setGeometry(200, 200, 100, 30)
        # 将按钮被点击时触发的信号与我们定义的函数click_my_btn进行绑定,即当按钮被触发会执行click_my_btn
        btn.clicked.connect(self.click_my_btn)

    def click_my_btn(self, arg):
        # 槽函数,点击按钮则调用该函数
        # 这里的参数正好是信号发出,传递的参数
        print("点击按钮啦~", arg)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()
    w.show()

    sys.exit(app.exec_())

信号和槽的案例二:自定义信号

import sys
import time

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

class MyWindow(QWidget):
    # 声明一个信号 只能放在函数的外面
    my_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.resize(300, 200)
        btn = QPushButton("开始检测", self)
        btn.setGeometry(100, 150, 100, 30)

        # 绑定按钮的点击,点击按钮则开始检测
        btn.clicked.connect(self.check)

        # 绑定信号和槽
        self.my_signal.connect(self.my_slot)

    def my_slot(self, msg):
        # 更新内容
        print(msg)

    def check(self):
        for i, ip in enumerate(["192.168.1.%d" % x for x in range(1, 255)]):
            msg = "模拟,正在检查 %s 上的漏洞...." % ip
            if i % 5 == 0:
                # 表示发射信号 对象.信号.发射(参数)
                self.my_signal.emit(msg + "【发现漏洞】") # 相当于调用了my_slot函数
	             
            time.sleep(0.01)
	
    '''
    	该自定义信号的执行顺序是: 先定义出自定义信号,接着将自定义信号和自定义槽函数绑定,截杀利用emit发送自定义信号,从而执行自定义槽函数
    '''

if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()
    w.show()

    sys.exit(app.exec_())
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值