PyQt5 基本语法(一):基类控件

基类控件

一、 简介

1、 什么是 Qt

使用 C++ 语言编写的跨平台 GUI 库,支持Windows 、MacOS和Linux。由于 Qt 使用C++语言编写,所以使用Qt开发的GUI程序的界面风格与当前操作系统完全相同,而且运行效率很高

2、 什么是PyQt

PyQt实现了一个Python模块集。它有超过300类,将近6000个函数和方法。它是一个多平台的工具包,可以运行在所有主要操作系统上,包括UNIX,Windows和Mac。 PyQt采用双许可证,开发人员可以选择GPL和商业许可。在此之前,GPL的版本只能用在Unix上,从PyQt的版本4开始,GPL许可证可用于所有支持的平台 ,同时Qt能实现的功能PyQt都能实现

3、 环境搭建

安装 PyQt5

pip install pyqt5

官方文档:【https://www.riverbankcomputing.com/static/Docs/PyQt5/sip-classes.html】

二、 基本结构

1、 第一个程序

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, qApp
import sys


# 创建一个应用程序
# sys.argv 当别人通过命令行执行这个程序的时候,可以设定一种功能(接收命令行传递的参数)
app = QApplication(sys.argv)
print(app.arguments())  # 得到命令行的参数
print(qApp.arguments())  # qApp为全局变量
# 创建一个窗口
w = QWidget()
# 窗口尺寸
w.resize(300, 150)
# 移动窗口,窗口左上角的坐标
w.move(300, 300)  
# 设置窗口的标题
w.setWindowTitle("第一个基于pyqt5的桌面应用")
# 设置标签
label = QLabel(w)
label.setText("hello world")
label.move(150, 75)
# 显示窗口
w.show()
# 进入程序的消息循环,并通过exit函数确保主循环安全结束,相当于无限循环
# 检测整个程序所接收到的用户交互信息
sys.exit(app.exec_())

2、 控件操作

步骤:

  • 创建控件

    • # 设置标签
      label = QLabel(contain)  
      

      参数:

      • contain:代表要在哪个控件(容器)上面展示,可以为空

      当我们创建一个控件之后,如果说,这个控件没有父控件,则把它当作顶层控件(窗口)

  • 设置控件

    • 大小,样式,位置,样式等
    • 顶层控件有权限去设置窗口内容,结构等
  • 展示控件

    • 当控件没有父控件时,要使用 show 方法去展示控件

3、 快速生成代码

在pycharm中的活动模板配置如下代码,快速生成代码

from PyQt5.Qt import *


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("$test$")  # 设置标题
        self.resize($500$, $500$)  # 设置窗口大小
        self.move($300$, $300$)  # 移动窗口
        self.setup_ui()  # 调用创建控件的方法

    def setup_ui(self):  # 添加控件的操作
        pass


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

4、 面向对象

提高代码的可维护性

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.QtWidgets import QApplication, QWidget, QLabel


class Window(QWidget):

    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle("Hello")  # 设置标题
        self.resize(300, 150)  # 设置窗口大小
        self.move(300, 300)  # 移动窗口
        self.setup_label()  # 调用创建控件的方法

    def setup_label(self):  # 添加控件的操作
        label = QLabel(self)
        label.setText("Hello World")
        label.move(150, 75)


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys
    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

三、 基类控件

什么是控件?

  • 一个程序界面上的各个独立的标准,一块矩形区域
  • 每类控件都具备不同的功能
  • 同时,有些控件有相似的功能,可以通过继承关系学习

1、 QObject

1.1 设置标识

1.1.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.Qt import *

obj = QObject(self)
obj.setObjectName("notice")  # 设置Qt对象名称
print(obj.objectName())  # 获得Qt对象名称
obj.setProperty("notice_l", "error")  # 设置对象的属性
obj.setProperty("notice_l2", "warning")
print(obj.property("notice_l"))  # 获得一个对象的属性值
print(obj.dynamicPropertyNames())  # 获取一个对象中所有通过setProperty设置的属性名称
1.1.2 应用场景
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.Qt import *


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("QObject")  # 设置标题
        self.resize(500, 300)  # 设置窗口大小
        self.move(500, 500)  # 移动窗口
        self.setup_ui()  # 调用创建控件的方法

    def setup_ui(self):  # 添加控件的操作
        self.qObject_ui()

    def qObject_ui(self):  # 所有类的基类
        # 案例演示
        label = QLabel(self)  # 创建标签
        label.setText("Hello")  # 设置标签内容
        label.setObjectName("notice")  # id 为 notice
        label.setProperty("level", "error")  # 属性选择器
        with open("QStyle.qss", "r") as f:
            """
            文件内容为:
            QLabel#notice[level='error'] {
            font-size: 20px;
            color: blue;
            }
            """
            qApp.setStyleSheet(f.read())
        # label.setStyleSheet("font-size: 20px; color: blue;")
        # qss 样式表,相当于前端的 css 样式表,可以将其放入一个 `.qss` 的文件中,方便分离和读取,同时,所有符合条件的内容都会变成相应的样式


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

1.3 父子对象

1.3.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *

obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj2.setParent(obj1)  # 设置父子关系
obj3.setObjectName("2")  # 设置id
obj3.setParent(obj2)
print(obj1, obj2.parent())  # 获取父类,返回内存地址
print(obj2, obj1.children())  # 获取所有直系子对象
print(obj1.findChild(QObject))  # 获取后代,递归查找,只返回一个
print(obj1.findChild(QObject, "2"))  # 获取id为2的后代,只返回一个
print(obj1.findChildren(QObject))  # 获取符合条件的所有后代
1.3.2 应用场景

内存管理机制,父控件删除,那么子控件也会自动删除

  • 按钮和对话框本身是父子控件关系
    • 当对话框被删除时,内部的子控件也会自动删除——非常合理
  • 我们操作的时候,是操作的对话框控件本身,而不是内部的子控件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *

obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2)
# 监听 obj2 对象被释放
obj2.destroyed.connect(lambda: print("obj2,被释放"))
print("删除父对象")
del obj1
print("删除完成")

如果一个控件,没有任何父控件,那么就会被当成顶层控件——多个顶层窗口相互独立

如果想要一个控件被包含在另外一个控件内部,就需要设置父子关系

  • 显示位置受父控件约束
  • 生命周期也被符对象接管

案例:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
win1 = QWidget()
win1.setStyleSheet("background-color: blue;")
win1.setWindowTitle("blue")
win1.resize(500, 500)
win1.show()

win2 = QWidget(win1)
win2.setStyleSheet("background-color: red;")
win2.setWindowTitle("red")
win2.resize(100, 100)
# win2.setParent(win1)  # win1 为父对象,win2 = QWidget(win1) 效果一样
win2.show()

l1 = QLabel()
b1 = QPushButton()
l1.setParent(win1)
b1.setParent(win1)
l1.setText("label")
b1.setText("button")
l1.move(200, 200)
b1.move(300, 200)
l2 = QLabel()
l2.setParent(win1)
l2.setText("Label")
l2.move(100, 200)

# 遍历设置样式
for i in win1.findChildren(QLabel):
    i.setStyleSheet("color: green;")

l1.show()
b1.show()
l2.show()


sys.exit(app.exec_())

1.4 信号操作

1.4.1 信号与槽机制

信号和槽是Qt中的核心机制,主要作用在于对象之间进行通讯

  • 当达到某个条件时,执行某个操作

信号(widget):

  • 当一个控件的状态发生改变时,向外发出信息

槽(connect):

  • 一个执行某些操作的函数/方法

所有继承自 QWidget 的控件都支持信号与槽机制

1.4.2 机制描述

手动操作:

  • 信号和槽相关联

自动操作:

  • 当信号发出时,连接槽函数会自动执行
1.4.3 信号处理

信号:

  • objectNameChange(objectName):对象名称发生改变时,发射此信号
  • destroyed(obj):对象被销毁时,发射信号
  • blockSignals(True):临时阻断连接
  • receivers(widget):查看当前信号连接了多少个槽
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *


def destroy():
    print("对象被摧毁")


obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2)
# obj.destroyed
obj1.destroyed.connect(lambda: destroy())

# obj.objectNameChanged
obj1.objectNameChanged.connect(lambda name: print("对象名称被改变: " + name))
obj1.setObjectName("xxx")

# obj1.objectNameChanged.disconnect()  # 断开槽与信号的连接
obj1.blockSignals(True)  # 临时阻断连接
obj1.setObjectName("1")
print("连接数量:" + str(obj1.receivers(obj1.objectNameChanged)))  # 查看有多少个槽连接这个信号

obj1.blockSignals(False)  # 再次开启连接
obj1.objectNameChanged.connect(lambda name: print("第二个连接:" + name))
print("连接数量:" + str(obj1.receivers(obj1.objectNameChanged)))  # 查看有多少个槽连接这个信号
obj1.setObjectName("2")
del obj2
1.4.4 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("test")  # 设置标题
        self.resize(300, 300)  # 设置窗口大小
        self.move(200, 300)  # 移动窗口
        self.setup_ui()  # 调用创建控件的方法

        def ret():
            print("标题变化了")
            # self.windowTitleChanged.disconnect()  # 断开槽与信号的关系
            self.blockSignals(True)  # 临时断开连接也行

        self.windowTitleChanged.connect(ret)

    def setup_ui(self):  # 添加控件的操作
        self.btn()  # 添加按钮

    def btn(self):
        b = QPushButton(self)
        b.setText("点击我")

        def ret():
            self.setWindowTitle("hello")

        b.clicked.connect(ret)


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

1.5 类型判定

1.5.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
obj = QObject(w)
w1 = QWidget(w)
l = QLabel(w)
print(w.isWidgetType())  # 判断是继承控件类型
print(obj.isWidgetType())  # 判断是否继承控件类型
print(l.isWidgetType())  # 判断是否继承控件类型
print(w.inherits("QWidget"))  # 判断是否继承控件类型
print(obj.inherits("QLabel"))  # 判断是否继承标签类型
print(l.inherits("QLabel"))  # 判断是否继承标签类型
sys.exit(app.exec_())
1.5.2 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("test")  # 设置标题
        self.resize(500, 500)  # 设置窗口大小
        self.move(300, 300)  # 移动窗口
        self.setup_ui()  # 调用创建控件的方法

    def setup_ui(self):  # 添加控件的操作
        l = QLabel(self)
        l.setText("first")
        l.move(100, 100)
        
        l2 = QLabel(self)
        l2.setText("second")
        l2.move(200, 100)
        
        btn = QPushButton(self)
        btn.setText("点我")
        btn.move(300, 100)
        
        for i in self.findChildren(QWidget):
            if i.inherits("QLabel"):  # 如果为 label 类型,修改样式
                i.setStyleSheet("color: red; font-size: 20px")
            else:
                i.setStyleSheet("color: blue; font-size: 20px")


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

1.6 对象删除

1.6.1 语法

删除一个对象时,也会解除它与父对象之间的关系

  • obj.deleteLater():其并没有将对象立即销毁,而是向主消息循环发送了一个event,下一次主消息循环收到这个event之后才会销毁对象
  • 这样做的好处是可以在这些延迟删除的时间里面完成一些操作;坏处是内存释放会不及时
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj3.setParent(obj2)
obj2.setParent(obj1)
obj1.destroyed.connect(lambda: print("obj1被释放"))
obj2.destroyed.connect(lambda: print("obj2被释放"))
obj3.destroyed.connect(lambda: print("obj3被释放"))
# obj1.deleteLater()
obj2.deleteLater()  # 等下一个循环开始时才会真正释放
# del obj2 # 直接删除,但是这是把变量和对象的关联替换了,使得系统无法访问对象,不是真的删除
print(obj1)
w.show()
sys.exit(app.exec_())

1.7 事件处理

信号与槽机制是对事件机制的高级封装

事件机制更偏离底层

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


class App(QApplication):

    def notify(self, rev, evt):
        if rev.inherits("QPushButton") and evt.type() == QEvent.MouseButtonPress:  # 过滤器,只查看按钮事件,并且只查看鼠标点击事件
            print("底层运行原理:")
            print(rev, evt)
        return super().notify(rev, evt)  # 分发事件


class Btn(QPushButton):
    def event(self, evt):
        if evt.type() == QEvent.MouseButtonPress:  # 事件过滤
            print("按钮点击了", evt)  # 里面很多事件
        return super().event(evt)

    def mousePressEvent(self, evt):
        print("鼠标被点击了。。。。。。。。。。")  # 如果只有这行代码的话,没有运行信号与槽的操作
        return super().mousePressEvent(evt)


app = App(sys.argv)
w = QWidget()
btn = Btn(w)
btn.setText("按钮")
btn.move(100, 100)
btn.pressed.connect(lambda: print("按钮被按下"))
btn.clicked.connect(lambda: print("按钮被点击"))
btn.released.connect(lambda: print("按钮被松开"))
w.show()
sys.exit(app.exec_())

1.8 定时器操作

1.8.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


class MyObject(QObject):

    def timerEvent(self, evt):
        print(evt, "1")  # 每个1秒打印
        return super().timerEvent(evt)


app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle("定时器")
w.resize(500, 500)
obj = MyObject()
t_id = obj.startTimer(1000)  # 1秒执行一次,通过继承的方法来启动计时器
obj.killTimer(t_id)  # 关闭定时器
w.show()
sys.exit(app.exec_())
1.8.2 应用场景
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


class MyLabel(QLabel):
    def __init__(self, sec, *args, **kwargs):  # 使用不定长参数传参
        super().__init__(*args, **kwargs)
        self.move(20, 20)
        self.setText(sec)
        self.setStyleSheet("font-size: 20px; color: red;")
        self.t_id = self.startTimer(1000)  # 1秒执行一次,通过继承的方法来启动计时器

    def timerEvent(self, evt):
        # 倒计时原理
        sec = int(self.text())
        sec -= 1
        self.setText(str(sec))
        if (sec == 0):
            self.killTimer(self.t_id)  # 关闭定时器


class MyQWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super(MyQWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle("定时器")
        self.resize(500, 500)
        self.startTimer(1000)  # 动画

    def timerEvent(self, evt):
        current_w, current_h = self.width(), self.height()
        if current_w > 1000 and current_h > 1000:
            current_w -= 20
            current_h -= 20
        elif current_h < 1000 and current_w < 1000:
            current_w += 20
            current_h += 20
        self.resize(current_w, current_h)


app = QApplication(sys.argv)
w = MyQWidget()
MyLabel("10", w)  # 同时,10秒倒计时
w.show()
sys.exit(app.exec_())

2、 QWidget

2.1 简介

介绍

  • 其为所有可视控件的基类

  • 是一个最简单的空白控件

  • 控件是用户界面的最小元素

    • 接收各种事件(鼠标、键盘等)
    • 绘制在桌面上面,展示给用户看
  • 每个控件都是矩形的,它们按Z轴顺序排序

  • 控件由其父控件和前面的控件剪切

  • 没有父控件的控件称之为窗口

2.2 继承

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *

print(QWidget.__bases__)  # 直系父类
print(QWidget.mro())  # 所有父类,祖宗类

父类几乎所有的方法,子类都可以使用

2.3 控件创建

语法:

w = QWidget(parent)  # 如果没有父类,可以不用填写

2.4 大小位置

2.4.1 获取

控件的坐标系统:

  • 以左上角为坐标原点,纵轴为垂直方向,横轴为水平方向

获取位置:

  • (x(), y()) / pos()
    • 相对于父控件的位置,包含窗口框架;顶层控件则相对于桌面的位置
    • QPoint(x, y)
  • (width(), height()) / size()
    • 控件的宽度和高度,不包含窗口框架
    • QSize(width, height)
  • geometry()
    • 用户区域相对于父控件的位置和尺寸的组合,不包含窗口框架
    • QRect(x, y, width, height)
  • rect()
    • 控件尺寸的组合,不包含窗口框架
    • QRect(0, 0, width, height)
  • frameSize()
    • 框架大小
  • frameGeometry()
    • 框架位置和尺寸
  • 注意:
    • 控件显示完毕之后,具体位置或者尺寸数据才会正确
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.move(100, 100)
w.resize(200, 200)
w.show()
# 桌面显示后获取的数据才准确
print(w.x())
print(w.width())
print(w.geometry())
print(w.rect())
print(w.frameSize())
print(w.frameGeometry())
sys.exit(app.exec_())
2.4.2 设置
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

""" 
move(x, y)  操作的是 x, y 也就是 pos,包含窗口框架
resize(width, height)  操作的是宽高:不包含窗口框架
setGeometry(x_noFrame, y_noFrame, width, height)  此处参照为用户区域,即不包含框架
adjustSize()  根据内容自适应大小
setFixedSize()  设置固定尺寸 
"""

app = QApplication(sys.argv)
w = QWidget()
"""
w.move(100, 100)
w.resize(200, 200)
# 下面这行代码和上面两行代码的作用类似
w.setGeometry(100, 100, 200, 200)
"""
w.setFixedSize(500, 500)  # 不可以修改它的大小
w.show()
sys.exit(app.exec_())

2.5 尺寸最值

2.5.1 获取

获取:

  • (minimumWidth(), minimumHeight()) / minimumSize()
    • 最小尺寸
  • (maximumWidth(), msximumHeight()) / maximumSize()
    • 最大尺寸
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
w.show()
print(w.minimumSize())  # 得到最小尺寸
print(w.maximumSize())  # 得到最大尺寸
sys.exit(app.exec_())
2.5.2 设置

设置最大最小尺寸

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
w.setMaximumWidth(1000)  # 限定最大宽度
w.setMaximumHeight(1000)  # 限定最大高度
w.setMaximumSize(1000, 1000)  # 限定最大宽度和高度
w.setMinimumSize(100, 100)  # 限定最小宽度和高度
w.setMinimumWidth(100)  # 限定最小宽度
w.setMinimumHeight(100)  # 限定最小高度
w.show()
sys.exit(app.exec_())

限定最值尺寸后,如果修改后的尺寸超过这个最值,最终大小为最值大小

2.6 内容边距

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)

l = QLabel(w)
l.setText("Hello World")
l.setStyleSheet("background-color: red; font-size: 20px; font-weight: 500;")
l.resize(300, 300)
l.setContentsMargins(110, 0, 0, 0)  # 设置内容外边距
print(l.contentsRect().getRect())  # 得到内容区域
print(l.getContentsMargins())  # 得到内容外边距

w.show()
sys.exit(app.exec_())

必须是控件本身有足够空间

2.7 鼠标相关

2.7.1 设置鼠标形状
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
pixmap = QPixmap(r"D:\35005\Pictures\Screenshots\微信图片_20220302175157.jpg")  # 传入图片设置鼠标图标
pixmap_new = pixmap.scaled(50, 50)  # 输入缩放的尺寸
cursor = QCursor(pixmap_new)  # 实例化鼠标对象
# w.setCursor(Qt.BusyCursor)  # 设置鼠标形状,参数里面输入鼠标样式
w.setCursor(cursor, 0, 0)  # 也可以传入一个鼠标对象,后面的数字传入的意思是以左上角为标准
w.unsetCursor()  # 取消设置鼠标的形状
w.show()
sys.exit(app.exec_())

常见的鼠标样式查询:https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtcore/qt.html#CursorShape

如果鼠标进入了控件的范围内,形状发生变化

2.7.2 重置鼠标形状
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
current_cursor = w.cursor()  # 获取鼠标对象
print(current_cursor.pos())  # 获得鼠标相对于电脑屏幕的位置坐标
current_cursor.setPos(10, 10)  # 设置鼠标的位置

w.show()
sys.exit(app.exec_())
2.7.3 鼠标跟踪

所谓的鼠标跟踪,其实就是设置检测鼠标移动事件的条件

鼠标跟踪:

  • 鼠标移动时,不处于按下状态,也会触发 mouseMoveEvent 事件

鼠标不跟踪:

  • 鼠标移动时,必须处于按下状态,才会触发 mouseMoveEvent 事件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


class MyWidget(QWidget):
    def mouseMoveEvent(self, me):
        print("鼠标移动了", me.localPos())  # 当不跟踪时,鼠标要按下才会触发
        # me.pos()和 me.localPos() 得到鼠标相对于控件的位置


app = QApplication(sys.argv)
w = MyWidget()
w.setWindowTitle("鼠标事件")
w.resize(500, 500)
w.setMouseTracking(True)  # 开启鼠标跟踪
print(w.hasMouseTracking())  # 判定是否开启鼠标跟踪
w.show()
sys.exit(app.exec_())
2.7.4 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


# 鼠标按下移动标签
class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.resize(500, 500)
        self.setWindowTitle("鼠标事件案例")
        self.label = QLabel(self)
        self.setup_ui()

    def mouseMoveEvent(self, me):
        x, y = me.x(), me.y()
        self.label.move(x, y)

    def setup_ui(self):
        self.label.resize(100, 100)
        self.label.setText("按住我!")
        self.label.setStyleSheet("background-color: green; font-weight: bold;")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())

2.8 事件

2.8.1 API

显示和关闭事件:

showEvent(QShowEvent)  # 控件显示是调用
closeEvent(QCloseEvent)  # 控件关闭时调用

移动事件:

moveEvent(QMoveEvent)  # 控件移动时调用

调整大小事件:

resizeEvent(QResizeEvent)  # 控件大小改变时调用

鼠标事件:

enterEvent(QEvent)  # 鼠标进入时触发
leaveEvent(QEvent)  # 鼠标离开时触发
mousePressEvent(QMouseEvent)  # 鼠标按下时触发
mouseReleaseEvent(QMouseEvent)  # 鼠标按下时触发
mouseDoubleClickEvent(QMouseEvent)  # 鼠标双击时触发
mouseMoveEvent(QMouseEvent)  # 鼠标按下后移动时触发,设置追踪后,没按下也能触发

键盘事件:

keyPressEvent(QKeyEvent)  # 键盘按下时使用
keyReleaseEvent(QKeyEvent)  # 键盘松开时使用

焦点事件:

focusInEvent(QFocusEvent)  # 获得焦点
focuseOutEvent(QFocusEvent)  # 失去焦点

拖拽事件:

dragEnterEvent(QDragEnterEvent)  # 拖拽进入控件时使用
dragLeaveEvent(QDragLeaveEvent)  # 拖拽离开控件时使用
dragMoveEvent(QDragMoveEvent)  # 拖拽在控件内移动时使用
dropEvent(QDropEvent)  # 拖拽放下时使用

绘制事件:

paintEvent(QPaintEvent)  # 显示控件,更新控件时使用

改变事件:

changeEvent(QEvent)  # 窗体改变,字体改变时调用

右键菜单:

contextMenuEvent(QContextMenuEvent)  # 访问右键菜单时使用

输入法:

inputMethodEvent(QInputMethodEvent)  # 输入法切换调用

当一个控件被触发了一个特定的行为时,就会调用特定的方法,来将事件传递给开发人员,方便处理

重写事件方法,就可以监听相关的信息


2.8.2 示例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("test")  # 设置标题
        self.resize(500, 500)  # 设置窗口大小
        self.move(100, 100)  # 移动窗口

    def showEvent(self, ev):
        print("窗口被展示了出来", ev)

    def closeEvent(self, ev):
        print("窗口关闭", ev)

    def moveEvent(self, ev):
        print("窗口移动", ev.pos())

    def resizeEvent(self, ev):
        print("控件大小改变", ev.size())

    def enterEvent(self, ev):
        print("鼠标进入了", ev)

    def leaveEvent(self, ev):
        print("鼠标离开了", ev)

    def mousePressEvent(self, ev):
        print("鼠标按下了", ev.button())

    def mouseReleaseEvent(self, ev):
        print("鼠标松开", ev)

    def mouseDoubleClickEvent(self, ev):
        print("鼠标双击了", ev.flags())

    def mouseMoveEvent(self, ev):
        print("鼠标在移动", ev)

    def keyPressEvent(self, ev):
        print("键盘按下了:", chr(ev.key()))

    def keyReleaseEvent(self, ev):
        print("键盘松开了:", chr(ev.key()))

    def focusInEvent(self, ev):
        print("获得焦点")

    def focusOutEvent(self, ev):
        print("失去焦点")


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())
2.8.3 事件传递

如果一个控件没有处理该事件,则会自动传递给父控件进行处理

事件对象具有两种特殊方法:

  • accept()
    • 自己处理这个事件,并告诉系统不要在向上层传递
  • ignore()
    • 自己忽略这个事件,但是会执行;告诉系统,继续往后传递
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


class Window(QWidget):
    def mousePressEvent(self, ev):
        print("顶层鼠标按下")


class MidWindow(QWidget):
    def mousePressEvent(self, ev):
        ev.ignore()  # 转发给父对象,但是也会接收对象
        print(ev.isAccepted())
        print("中间鼠标按下")


class Label(QLabel):
    def mousePressEvent(self, ev):
        print("标签控件鼠标按下")
        ev.accept()  # 不用转发给父对象,接收对象
        print(ev.isAccepted())


app = QApplication(sys.argv)
w = Window()
w.setWindowTitle("事件转发")
w.resize(500, 500)
m_w = MidWindow(w)
m_w.resize(300, 300)
m_w.setAttribute(Qt.WA_StyledBackground, True)
m_w.setStyleSheet("background-color: yellow;")

label = Label(m_w)
label.setText("这是一个标签")
label.setStyleSheet("background-color: skyblue;")
label.move(110, 110)
# 注意这个底层事件会被顶层事件覆盖

w.show()
sys.exit(app.exec_())
2.8.4 案例
  1. 创建一个窗口包含一个标签

    • 鼠标进入标签时,展示欢迎光临
    • 鼠标离开标签时,展示谢谢惠顾
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    # @author: kun
    from PyQt5.Qt import *
    import sys
    
    
    class Label(QLabel):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.resize(200, 200)
            self.move(100, 100)
            self.setStyleSheet("background-color: skyblue;")
    
        def enterEvent(self, *args, **kwargs):
            self.setText("欢迎光临")
    
        def leaveEvent(self, *args, **kwargs):
            self.setText("谢谢惠顾")
    
    
    app = QApplication(sys.argv)
    w = QWidget()
    w.setWindowTitle("鼠标操作案例1")
    w.resize(500, 500)
    label = Label(w)
    w.show()
    sys.exit(app.exec_())
    
  2. 创建一个窗口,监听用户按键

    • 监听用户输入Tab键
    • 监听用户输入Ctrl + S 组合键
    • 监听用户输入Ctrl + Shift + v 组合键
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    # @author: kun
    from PyQt5.Qt import *
    import sys
    
    
    class Label(QLabel):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.resize(200, 200)
            self.move(100, 100)
            self.setStyleSheet("background-color: skyblue; font-weight: 500;")
            self.grabKeyboard()  # 捕获键盘事件
            # self.releaseKeyborad()  # 停止捕获键盘事件
    
        def keyPressEvent(self, ev):
            # 监听 Tab 键
            if ev.key() == Qt.Key_Tab:  # 监听普通键
                self.setText('用户点击的是Tab键')
            # 监听 Ctrl + C  修饰键 Ctrl 并且 普通键 C  Qt.AltModifier:其为 Alt 组合键
            if ev.modifiers() == Qt.ControlModifier and ev.key() == Qt.Key_C:
                self.setText("正在复制文本内容")
            # 监听 Ctrl + Shift + v 修饰键 Ctrl + Shift (使用按位或组合获取) 并且普通键 V
            if ev.modifiers() == Qt.ControlModifier | Qt.ShiftModifier and ev.key() == Qt.Key_V:
                self.setText("正在粘贴内容")
    
    
    app = QApplication(sys.argv)
    w = QWidget()
    w.setWindowTitle("鼠标操作案例1")
    w.resize(500, 500)
    label = Label(w)
    w.show()
    sys.exit(app.exec_())
    
  3. 完成窗口,用户区支持拖拽

    • 确定鼠标移动的距离(向量 x, y)
    • 原始窗口坐标点 + 向量
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    # @author: kun
    from PyQt5.Qt import *
    
    
    class Window(QWidget):
    
        def __init__(self):
            super().__init__()
            self.move_flag = False  # 判断是否在移动
            self.setWindowTitle("内容拖动")  # 设置标题
            self.resize(500, 500)  # 设置窗口大小
            self.move(100, 100)  # 移动窗口
            self.mouse = ()  # 移动前的坐标
            self.origin = ()  # 原始的坐标
    
        def mousePressEvent(self, evt):
            """
            print(evt.localPos())  # 得到是相对于窗口左上角的坐标
            print(evt.globalPos())  # 得到的是相对于电脑左上角的坐标
            """
            if evt.button() == Qt.LeftButton:
                self.move_flag = True  # 设定标记
                self.mouse = (evt.globalX(), evt.globalY())  
                self.origin = (self.x(), self.y())  # 左上角坐标
    
        def mouseMoveEvent(self, evt):
            if self.move_flag:
                # 相对移动
                move_x = evt.globalX() - self.mouse[0]
                move_y = evt.globalY() - self.mouse[1]
                self.move(self.origin[0] + move_x, self.origin[1] + move_y)
    
        def mouseReleaseEvent(self, evt):
            # 确定最终位置
            self.move_flag = False
    
    
    if __name__ == '__main__':
        # 可以通过导包来运行窗口
        import sys
    
        app = QApplication(sys.argv)
        # 创建窗口
        w = Window()
        # 显示窗口
        w.show()
        sys.exit(app.exec_())
    

2.9 父子关系

2.9.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle("父子关系")
w.resize(500, 500)

l1 = QLabel(w)
l1.setText("标签1")

l2 = QLabel(w)
l2.setText("标签2")
l2.move(50, 0)

l3 = QLabel(w)
l3.setText("标签3")
l3.move(100, 0)

print(w.childAt(50, 0))  # 获得对应坐标的子控件
print(l2.parentWidget())  # 获得父控件
print(w.childrenRect().getRect())  # 打印子控件所占有的矩形区域

w.show()
sys.exit(app.exec_())
2.9.2 案例

创建窗口,若干个Label控件,实现点击功能

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys


# class MyLabel(QLabel):  # 借助子控件
#     def mousePressEvent(self, evt):
#         for i in self.parentWidget().findChildren(MyLabel):  # 获取父控件
#             i.setStyleSheet("")
#         self.setStyleSheet("background-color: red;")

class MyWidget(QWidget):
    def mousePressEvent(self, evt):
        subLabel = self.childAt(evt.x(), evt.y())
        if subLabel:  # 如果点击了标签;避免了报错
            for i in self.findChildren(QLabel):  # 获取所有子控件,并清空样式
                i.setStyleSheet("")
            subLabel.setStyleSheet("background-color: red;")  # 给制定内容修改样式


app = QApplication(sys.argv)
w = MyWidget()
w.setWindowTitle("父子关系")
w.resize(500, 500)
for i in range(11):
    l = QLabel(w)
    l.setText(f"标签{i}")
    l.move(50 * i, 50 * i)

w.show()
sys.exit(app.exec_())

2.10 层级控制

高层级控件会被低层级控件覆盖

语法:

lower()  # 将控件层级降低到最底层
raise_()  # 将控件提升到最上层
a.stzckUnder(b)  # 让 a 放在 b 下面

注意:以上操作专指同级顺序

应用:需要调整控件Z轴顺序

2.11 顶层窗口

2.11.1 基本语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
icon = QIcon(r"D:\35005\Pictures\Screenshots\微信图片_20220302175157.jpg")  # 创建图标对象
w.setWindowIcon(icon)  # 设置窗口图标
print(w.windowIcon())  # 获取图标对象
w.setWindowTitle("Hello")  # 默认为 python
print(w.windowTitle())  # 获取窗口的标题
w.setWindowOpacity(0.9)  # 设置不透明度,范围是 0 ~ 1
print(w.windowOpacity())  # 获取窗口不透明度
w.setWindowState(Qt.WindowActive)
# 设置窗口状态,有 无状态(WindowNoSate) 最小化(WindowMinimized)
# 最大化(WindowMaximized) 全屏(WindowFullScreen) 活动窗口(WindowActive)
print(w.windowState())  # 获取窗口状态
w.show()
sys.exit(app.exec_())
2.11.2 最大化和最小化
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
# w.showMaximized()  # 最大化展示
# w.showMinimized()  # 最小化展示
# w.showNormal()  # 正常展示
# w.showFullScreen()  # 全屏展示
print(w.isMinimized())  # 查看是否为最小化
print(w.isMaximized())  # 查看是否为最大化
print(w.isFullScreen())  # 查看是否为全屏
w.show()
sys.exit(app.exec_())
2.11.3 窗口标志
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()
w.setWindowFlags(Qt.WindowStaysOnTopHint)  # 设置顶层窗口的外观标志
w.show()
sys.exit(app.exec_())
属性 描述
Qt.MSWindowsFixedSizeDialogHint 固定窗口,无法调整大小
Qt.FramelessWindowHint 窗口无边框
Qt.CustomizeWindowHint 有边框,无标题栏与按钮,不能移动和拖动
Qt.WindowTitleHint 添加标题栏与关闭按钮
Qt.WindowSystemMenuHint 添加系统目录和关闭按钮
Qt.WindowMaximizeButtonHint 激活最大化按钮与关闭按钮,禁止最小化按钮
Qt.WindowMinimizeButtonHint 激活最小化按钮与关闭按钮,禁止最大化按钮
Qt.WindowMinMaxButtonsHint 激活最大化与最小化按钮和关闭按钮
Qt.WindowCloseButtonHint 添加一个关闭按钮
Qt.WindowContextHelpButtonHint 添加问号与关闭按钮,像对话框一样
Qt.WindowStaysOnTopHint 窗口始终处于顶部位置
Qt.windowStaysOnButtonHint 窗口始终处于底部位置
2.11.4 案例

创建一个窗口,要求:

  • 无边框,无标题栏
  • 窗口半透明
  • 自定义最大化,最小化,关闭按钮
  • 支持拖拽用户区移动
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *


class Window(QWidget):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("案例")  # 设置标题
        self.move_flag = False  # 默认没有移动
        self.resize(500, 500)  # 设置窗口大小
        self.move(300, 300)  # 移动窗口
        self.setWindowOpacity(0.9)  # 设置窗口透明
        self.setup_ui()  # 调用创建控件的方法
        self.origin = ()  # 初始坐标,相对于窗口的
        self.mouse = ()  # 鼠标按下时,鼠标相对于窗口的坐标

    def setup_ui(self):  # 添加控件的操作
        def close_w():
            self.deleteLater()  # 删除主窗口

        btn_close = QPushButton(self)
        btn_close.clicked.connect(close_w)
        btn_close.setText("X")
        btn_close.move(self.width() - 25, 8)

        def max_or_min(btn):
            if self.isMaximized():
                self.showNormal()
                btn.setText("+")
            else:
                self.showMaximized()
                btn.setText("-")
            count = 1
            self.findChild(QLabel).resize(self.width(), 45)
            for i in self.findChildren(QPushButton):
                i.move(self.width() - count * 25, 8)  # 动态化设置按键的位置
                count += 1

        btn_maxOrMin = QPushButton(self)
        btn_maxOrMin.move(self.width() - 50, 8)
        btn_maxOrMin.clicked.connect(lambda: max_or_min(btn_maxOrMin))
        btn_maxOrMin.setText("+")  
        qApp.setStyleSheet("""QPushButton{  
            font-size: 20px;
            color: black;
            font-weight: 800;
            border: 2px solid black;
            margin: 5px;
        }""")  # 设置样式
        # 设置窗口头部框架
        label = QLabel(self)
        label.resize(self.width(), 45)
        label.setStyleSheet("background-color: skyblue;")
        label.lower()

    # 设置窗口移动
    def mousePressEvent(self, evt):
        if evt.button() == Qt.LeftButton:
            self.move_flag = True
            self.mouse = (evt.globalX(), evt.globalY())
            self.origin = (self.x(), self.y())

    def mouseMoveEvent(self, evt):
        self.move(evt.globalX() - self.mouse[0] + self.origin[0],
                  evt.globalY() - self.mouse[1] + self.origin[1]) if self.move_flag else None

    def mouseReleaseEvent(self, *args, **kwargs):
        self.move_flag = False


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口,同时无边框,无标题栏
    w = Window(flags=Qt.FramelessWindowHint)
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

2.12 交互状态

2.12.1 是否可见
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
setEnabled(bool)  # 设置控件是否可用
isEnabled()  # 获取控件是否可用
"""
app = QApplication(sys.argv)
w = QWidget()
btn = QPushButton(w)
btn.setText("点击")
print(btn.isEnabled())  # 判断按钮是否可用
btn.pressed.connect(lambda: btn.setEnabled(False))  # 点击后按钮禁用
w.show()
sys.exit(app.exec_())
2.12.2 显示和隐藏
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

"""
# 显示和隐藏
setVisible(bool)  # 设置控件是否可见,传递的参数值为 True 也不一定可见,如果父控件没有展示,那么子控件为 True 也不可见
    setHidden(bool)  # 设置隐藏
    show()  # 设置显示
    hide()  # 设置隐藏
isHidden()  #  获取相对于父控件是否隐藏
isVisible()  # 获取是否可见
isVisibleTo(widget)  # 获取相对于widget控件是否可见,即该控件是否跟着widget控件一起显示 
"""

app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
btn = QPushButton(w)
print(btn.isVisible())  # 判断控件是否可见
btn.clicked.connect(lambda: btn.hide())  # 隐藏按钮
print(w.isHidden())  # 判断窗口是否隐藏
w.setVisible(True)  # 使得窗口可见,先绘制父窗口
# w.setHidden(False)  # 效果一样
sys.exit(app.exec_())
2.12.3 是否可编辑
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

"""
setWindowModified(bool)  # 设置是否被编辑
isWindowModified()  # 窗口是否被编辑
"""

app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle("[*]交互状态")
w.setWindowModified(True)  # 可编辑状态会显示 [] 里面的*号,即有 * 号就处于被编辑状态
print(w.isWindowModified())  # 判断窗口是否处于可编辑状态
w.setVisible(True)  # 和show作用类似
sys.exit(app.exec_())
2.12.4 是否为活跃窗口
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w1 = QWidget()
w2 = QWidget()
w2.show()
w1.show()
print(w2.isActiveWindow())  # 展示是否处于活跃窗口
print(w1.isActiveWindow())
sys.exit(app.exec_())
2.12.5 控件关闭
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

"""
setAttribute(Qt.WA_DeleteOnClose, True)  # 如果加了这行代码,窗口/控件就会在关闭的同时删除,效果和deleteLater类似
close()  # 效果和setVisible类似
"""

app = QApplication(sys.argv)
w1 = QWidget()
w2 = QWidget()
w2.destroyed.connect(lambda: print("w2销毁"))
w1.destroyed.connect(lambda: print("w1销毁"))
w2.show()
w1.show()
w1.setAttribute(Qt.WA_DeleteOnClose, True)  # 如果加了这行代码,窗口/控件就会在关闭的同时删除,效果和deleteLater类似
w1.close()  # 效果和setVisible类似
w2.setVisible(False)  # 使得窗口不可见,但是窗口并没有删除
w2.deleteLater()  # 销毁窗口/控件
sys.exit(app.exec_())
2.12.6 案例

创建一个窗口,包含一个文本框和一个按钮和一个标签:

  • 默认状态下,标签隐藏,文本框和按钮显示,按钮为不可使用状态
  • 当文本框有内容时,让按钮可用,否则不可用
  • 当文本框内容为kun时,点击按钮显示标签,并且展示文本为登录成功,否则为失败

涉及知识点:

  • 文本框的创建
    • QLineEdit类
  • 文本框内容监测
    • testChanged 信号
  • 文本框内容获取
    • text() 方法
  • 按钮状态设置
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import hashlib


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("案例[*]")  # 设置标题
        self.resize(500, 500)  # 设置窗口大小
        self.move(100, 100)  # 移动窗口
        self.setup_ui()  # 调用创建控件的方法

    def setup_ui(self):  # 添加控件的操作 5 + 40 + 5 + 40 + 5
        qApp.setStyleSheet("*{font-size: 15px; line-height: 15px;}")  # 设置样式
        # 创建文本框
        text = QLineEdit(self)
        text.resize(300, 40)
        text.move(100, 5)

        def change_():
            self.setWindowModified(True)
            btn.setEnabled(len(text.text()) > 0)  # 当有文本框内容时,按钮可用

        text.textChanged.connect(change_)  # 绑定事件
        # 创建按钮
        btn = QPushButton(self)
        btn.resize(80, 40)
        btn.setText("登录")
        btn.move(210, 50)
        btn.setEnabled(False)  # 按钮不可用

        def click_():
            label.setVisible(True)  # 显示标签
            # 使用 hash 加密
            salt = hashlib.md5("liu".encode("utf-8"))
            salt.update(text.text().encode("utf-8"))
            content = salt.hexdigest()
            if content == 'a8b2a2561ec21479990c48706a743c9a':  # 条件判断
                label.setText("登录成功")
            else:
                label.setText("登录失败")

            text.setText("")
            self.setWindowModified(False)

        btn.clicked.connect(click_)  # 绑定事件
        # 创建标签
        label = QLabel(self)
        label.resize(100, 40)
        label.move(220, 95)
        label.setVisible(False)  # 标签隐藏


if __name__ == '__main__':
    # 可以通过导包来运行窗口
    import sys

    app = QApplication(sys.argv)
    # 创建窗口
    w = Window()
    # 显示窗口
    w.show()
    sys.exit(app.exec_())

2.13 信息提示

2.13.1 状态提示

鼠标悬停在空间上一会儿后,展示内容在状态栏上面

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QMainWindow()  # 使用组合窗口
w.resize(500, 500)
w.statusBar()  # 创建状态栏,可以显示状态提示
l = QLabel(w)
l.setStatusTip("这是信息提示")   # 设置状态提示
l.setText("你好")
print(l.statusTip())  # 获取状态提示
w.show()
sys.exit(app.exec_())
2.13.2 工具提示

鼠标悬停在控件上一会儿后,展示在旁边

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget()  
w.resize(500, 500)
l = QLabel(w)
l.setToolTip("这是一个工具提示")
l.setText("坤坤")
l.setToolTipDuration(1000)  # 工具提示展示时间为 1 秒
print(l.toolTip())  # 获取工具提示
w.show()
sys.exit(app.exec_())
2.13.3 意思提示

切换到查看这是啥模式,点击该控件时显示

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)
w = QWidget(flags=Qt.WindowContextHelpButtonHint)  # 这是啥模式
w.resize(500, 500)
l = QLabel(w)
l.setWhatsThis("这是啥,这是一个意思提示")  # 设置一个意思提示
l.setText("坤坤")
print(l.whatsThis())  # 获取意思提示
w.show()
sys.exit(app.exec_())

2.14 焦点控制

2.14.1 单个控件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
setFocus()  # 指定控件获取焦点
setFocusPolicy(mode)  # 设置焦点获取策略
    - 参数
        Qt.TabFocus    通过 Tab 获取焦点
        Qt.ClickFocus  通过点击获取焦点
        Qt.StrongFocus 通过以上两种方式获取焦点
        Qt.NoFocus     不能通过以上两种方式获取焦点
clearFocus()  # 取消焦点
"""


app = QApplication(sys.argv)
# 创建三个文本框
w = QWidget()
w.resize(500, 500)
t1 = QLineEdit(w)
t2 = QLineEdit(w)
t2.move(50, 50)
t2.setFocus()  # 设置焦点
t2.setFocusPolicy(Qt.TabFocus)  # 获取焦点的方式
t2.clearFocus()  # 取消焦点
t3 = QLineEdit(w)
t3.move(100, 100)
w.show()
sys.exit(app.exec_())
2.14.2 父控件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
focusWidget()  # 获取子控件中当前焦距的控件
focusNextChild()  # 聚焦下一个子控件
focusPreviousChild()  # 聚焦上一个子控件
focusNextPrevChild()  # true:下一个 false:上一个
setTabOrder(pre_widget, next_widget)  # 静态方法,用于设置子控件获取焦点的先后顺序
"""


app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
t1 = QLineEdit(w)
t1.setFocus()  # 给 t1 设置焦点
t2 = QLineEdit(w)
t2.move(50, 50)
t3 = QLineEdit(w)
t3.move(100, 100)
w.show()
# QWidget.setTabOrder(t3, t2)  # 按 tab 获取焦点的顺序 t3 > t2 > t1
w.focusNextChild()  # 聚焦下一个子控件
w.focusNextPrevChild(True)  # 结果是t3有焦点
print(w.focusWidget())  # 获取子控件中当前焦距的控件
sys.exit(app.exec_())

2.15 信号

windowTitleChanged(QString)  # 窗口标题改变信号
windowIconChanged(QIcon)  # 窗口图标改变信号
customContentMenuRequested(Qpoint)  # 自定义上下文菜单请求信号

基类控件学习完成,下面我们开始学习具体的子类控件

posted @ 2022-03-29 13:47  A-L-Kun  阅读(566)  评论(2编辑  收藏  举报