1.窗口

 1 在Qt中,生成窗口有三种方式,分别为:QWidget | QMainWindow | QDialog
 2 
 3 QWidget
 4 
 5 控件和窗口的父类,自由度高(什么东西都没有),没有划分菜单,工具栏,主窗口等区域
 6 
 7 QMainWindow
 8 
 9 是QWidget的子类,包含菜单栏,工具栏,状态栏,标题栏等,中间部分则为主窗口区域
10 
11 QDialog
12 
13 对话框窗口的基类

 

1.1QWidget

 

1.2.QMainWindow

 1 import sys
 2 from PyQt5.QtWidgets import QMainWindow, QLabel, QApplication
 3 
 4 
 5 class MyWindow(QMainWindow):
 6     def __init__(self):
 7         super().__init__()
 8         self.init_ui()
 9 
10     def init_ui(self):
11         label = QLabel("这是文字~~")
12         label.setStyleSheet("font-size:30px;color:red")
13         # 调用父类中的menuBar,从而对菜单栏进行操作
14         menu = self.menuBar()
15         # 如果是Mac的话,菜单栏不会在Window中显示而是屏幕顶部系统菜单栏位置
16         # 下面这一行代码使得Mac也按照Windows的那种方式在Window中显示Menu
17         menu.setNativeMenuBar(False)
18         file_menu = menu.addMenu("文件")
19         file_menu.addAction("新建")
20         file_menu.addAction("打开")
21         file_menu.addAction("保存")
22         edit_menu = menu.addMenu("编辑")
23         edit_menu.addAction("复制")
24         edit_menu.addAction("粘贴")
25         edit_menu.addAction("剪切")
26         # 设置中心内容显示
27         self.setCentralWidget(label)
28 
29 
30 if __name__ == '__main__':
31     app = QApplication(sys.argv)
32     w = MyWindow()
33     # 设置窗口标题
34     w.setWindowTitle("我是窗口标题....")
35     # 展示窗口
36     w.show()
37     # 程序进行循环等待状态
38     app.exec()

 

1.3.QDialog

​ 不过对话框一般不应该作为主窗口的存在,而是通过点击操作弹出,起到提示作用

 

 !!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!

2.信号与槽*****************(信号与槽是Qt的核心内容)

 1 1.信号(signal)
 2 ​ 其实就是事件(按钮点击、内容发生改变、窗口的关闭事件)或者是状态(check选中了,togglebutton切换)。当程序触发了某种状态或者发生了某种事件(比如:按钮被点击了,内容改变等等),那么即可发射出来一个信号。
 3 
 4 2.槽(slot)
 5 ​ 若向捕获这个信号,然后执行相应的逻辑代码,那么就需要使用到槽,槽实际上是一个函数,当信号发射出来后,会执行与之绑定的槽函数。
 6 
 7 3.将信号与槽链接
 8 ​ 为了能够实现,当点击某个按钮时执行某个逻辑,需要把具体的信号和具体的槽函数绑定到一起。操作大体流程如下:
 9 
10 对象.信号.connect(槽函数)

 需求:

当出现了某一种信号(某一种事件)的时候,我们需要执行一段代码(用函数来包装这份代码-----信号和槽)

案例1:接收信号

 1 import sys
 2 from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
 3 
 4 
 5 class MyWindow(QWidget):
 6     def __init__(self):
 7         super().__init__()
 8         self.init_ui()
 9 
10     def init_ui(self):
11         # 更改当前窗口的宽高
12         self.resize(500, 300)
13         # 创建一个按钮
14         btn = QPushButton("点我点我", self)
15         # 设置窗口位置、宽高
16         btn.setGeometry(200, 200, 100, 30)
17         # 将按钮被点击时触发的信号与我们定义的函数(方法)进行绑定
18         # 注意:这里没有(),即写函数的名字,而不是名字()
19         btn.clicked.connect(self.click_my_btn)
20 
21     def click_my_btn(self, arg):
22         # 槽函数,点击按钮则调用该函数
23         # 这里的参数正好是信号发出,传递的参数
24         print("点击按钮啦~", arg)
25 
26 
27 if __name__ == '__main__':
28     app = QApplication(sys.argv)
29     w = MyWindow()
30     w.show()
31     app.exec()

 

案例2:自定义信号【重点】

​ 除了接收Qt自带的信号之外,我们也可以自行定义信号,在合适的时机,自行发射信息。自定义信号需要使用到 pyqtSignal 来声明信号,并且需要在类中的函数之外声明。如果会自定义信号,那么信号和槽基本就掌握了。否则永远只会接收别人发射出的信号。

 1 import sys
 2 import time
 3 from PyQt5.QtWidgets import *
 4 from PyQt5.QtCore import *
 5 
 6 
 7 class MyWindow(QWidget):
 8     # 声明一个信号 只能放在函数的外面
 9     my_signal = pyqtSignal(str)
10 
11     def __init__(self):
12         super().__init__()
13         self.init_ui()
14         self.msg_history = list()  # 用来存放消息
15 
16     def init_ui(self):
17         self.resize(500, 200)
18         # 创建一个整体布局器
19         container = QVBoxLayout()
20         # 用来显示检测到漏洞的信息
21         self.msg = QLabel("")
22         self.msg.resize(440, 15)
23         # print(self.msg.frameSize())
24         self.msg.setWordWrap(True)  # 自动换行
25         self.msg.setAlignment(Qt.AlignTop)  # 靠上
26         # self.msg.setStyleSheet("background-color: yellow; color: black;")
27         # 创建一个滚动对象
28         scroll = QScrollArea()
29         scroll.setWidget(self.msg)
30         # 创建垂直布局器,用来添加自动滚动条
31         v_layout = QVBoxLayout()
32         v_layout.addWidget(scroll)
33         # 创建水平布局器
34         h_layout = QHBoxLayout()
35         btn = QPushButton("开始检测", self)
36         # 绑定按钮的点击,点击按钮则开始检测
37 
38         btn.clicked.connect(self.check)
39 
40         h_layout.addStretch(1)  # 伸缩器
41         h_layout.addWidget(btn)
42         h_layout.addStretch(1)
43         # 操作将要显示的控件以及子布局器添加到container
44         container.addLayout(v_layout)
45         container.addLayout(h_layout)
46         # 设置布局器
47         self.setLayout(container)
48         # 绑定信号和槽
49         self.my_signal.connect(self.my_slot)
50 
51     def my_slot(self, msg):
52         # 更新内容
53         print(msg)
54         self.msg_history.append(msg)
55         self.msg.setText("<br>".join(self.msg_history))
56         self.msg.resize(440, self.msg.frameSize().height() + 15)
57         self.msg.repaint()  # 更新内容,如果不更新可能没有显示新内容
58 
59     def check(self):
60         for i, ip in enumerate(["192.168.1.%d" % x for x in range(1, 255)]):
61             msg = "模拟,正在检查 %s 上的漏洞...." % ip
62             # print(msg)
63             if i % 5 == 3:
64                 # 表示发射信号 对象.信号.发射(参数)
65                 self.my_signal.emit(msg + "【发现漏洞】")
66             time.sleep(0.01)
67 
68 
69 if __name__ == '__main__':
70     app = QApplication(sys.argv)
71     w = MyWindow()
72     w.show()
73     app.exec()

 

 

3.QT Designer

3.1.使用流程

  1. 创建一个基于QWidget的界面

  1. 此时会创建一个新的窗口,如下效果

 

  1. 拖动想要的控件

 

  1. 选中控件,看属性

  1. 修改属性

 

 其实我们可以看到都是一堆前端代码写出来的页面

  6.信号与槽

通过这个app左下序号的操作,可以将“点我”这个按钮点击触发的信号与LCDNumber进行关联,从而实现信号与槽的绑定(双击点击下拉选择)

 在这里我设置这样的信号与槽,信号的发送者是pushButton,触发条件是当按钮被点击时,信号的接受者为lcdNumber,接受者的执行动作为接受到信号后关闭。然后保存文件,放在pycharm解释器中,写脚本测试

 

练习

 目的:获取用户名、密码,在TextBrowser中显示一些登录的信息

​ 使用的技术:python加载.ui文件获取了界面,对.ui文件中的控件操作,完成信号与槽的绑定等。

首先我们print(self.ui.__dict__) ,查看ui文件中有哪些控件,发现打印出来的数量正好与在设计.ui文件时控件的数量一致,这里我就不放打印出来的图片啦

 1 import sys
 2 from PyQt5.QtWidgets import *
 3 from PyQt5 import uic
 4 
 5 
 6 class MyWindow(QWidget):
 7     def __init__(self):
 8         super().__init__()
 9         self.init_ui()
10 
11     def init_ui(self):
12         self.ui = uic.loadUi(r"C:\Users\19225\PycharmProjects\test\src\user\static\login.ui")
13         # print(self.ui.__dict__)  # 查看ui文件中有哪些控件
14         # 提取要操作的控件
15         self.user_name_qwidget = self.ui.lineEdit  # 用户名输入框
16         self.password_qwidget = self.ui.lineEdit_2  # 密码输入框
17         self.login_btn = self.ui.pushButton  # 登录按钮
18         self.forget_password_btn = self.ui.pushButton_2  # 忘记密码按钮
19         self.textBrowser = self.ui.textBrowser  # 文本显示区域
20         # 绑定信号与槽函数
21         self.login_btn.clicked.connect(self.login)
22 
23     def login(self):
24         """登录按钮的槽函数"""
25         user_name = self.user_name_qwidget.text()
26         password = self.password_qwidget.text()
27         if user_name == "admin" and password == "123456":
28             self.textBrowser.setText("欢迎%s" % user_name)
29             self.textBrowser.repaint()
30         else:
31             self.textBrowser.setText("用户名或密码错误....请重试")
32             self.textBrowser.repaint()
33         其他逻辑自己添加吧
34 --------------------------------------------------------------------------------------
35 if __name__ == '__main__':
36     app = QApplication(sys.argv)
37     w = MyWindow()
38     # 展示窗口
39     w.ui.show()
40     app.exec()

    

 

 

4.PyQt多线程

 1 多线程与多进程的概念
 2 
 3 多线程 (Multithreading)
 4 
 5 定义:多线程是在单个进程内运行多个线程,每个线程可以执行不同的任务。线程是操作系统调度的基本单位。
 6 共享内存空间:线程共享同一个进程的内存空间,因此可以轻松地共享数据,但这也带来了线程安全的问题。
 7 轻量级:线程比进程更轻量级,创建和销毁的开销较小。
 8 适用场景:适用于I/O密集型任务,如文件读写、网络请求等,因为这些任务往往在等待I/O操作完成时会阻塞线程,但其他线程可以继续执行。
 9 
10 
11 多进程 (Multiprocessing)
12 
13 定义:多进程是在操作系统内同时运行多个进程,每个进程拥有独立的内存空间和资源。
14 独立内存空间:进程之间不共享内存空间,这使得它们之间的数据共享需要通过进程间通信(IPC)机制,如管道、消息队列等。
15 重量级:进程比线程更重量级,创建和销毁的开销较大。
16 适用场景:适用于CPU密集型任务,如复杂计算、数据处理等,因为每个进程可以独立运行在多核CPU上,充分利用多核处理能力。
多线程与多进程的区别
 1 资源使用:
 2 多线程:共享同一进程的内存空间和资源,线程间通信(如通过全局变量或共享对象)更加便捷,但需要处理线程同步问题。
 3 
 4 多进程:每个进程有独立的内存空间和资源,进程间通信相对复杂,但能提供更好的隔离性和稳定性。
 5 
 6 开销:
 7 多线程:创建和销毁的开销较小,适合轻量级的并发任务。
 8 多进程:创建和销毁的开销较大,但适合需要隔离资源和独立运行的重任务。
 9 
10 安全性:
11 多线程:由于共享内存空间,线程安全(如竞争条件、死锁)是一个重要问题,需要使用锁、信号量等机制。
12 多进程:各进程独立运行,安全性较高,不会出现线程间资源竞争的问题。
13 
14 性能:
15 多线程:适合I/O密集型任务,可以提高程序的响应速度和处理效率。
16 多进程:适合CPU密集型任务,可以充分利用多核CPU的计算能力,提高计算效率。

 

 应用场景
1 多线程应用场景
2 GUI应用:在GUI应用中,多线程可以用来处理后台任务(如文件下载、数据加载),以避免阻塞主线程,使界面保持响应。
3 
4 网络应用:网络服务器、爬虫等需要处理大量I/O操作的应用,可以使用多线程来处理多个客户端连接或请求。
5 
6 多进程应用场景
7 数据处理:在数据分析、科学计算等需要大量CPU计算的任务中,多进程可以显著提高计算速度。
8 
9 独立任务:需要运行彼此独立的任务(如不同的子进程执行不同的任务),避免相互干扰,提高程序的健壮性和稳定性。

 

4.1.引入

​将上面讲解的登录的按钮示例,适当修改代码,详细代码如下:

 1 import sys
 2 import time
 3 from PyQt5.QtWidgets import *
 4 from PyQt5 import uic
 5 from threading import Thread
 6 
 7 
 8 class MyWindow(QWidget):
 9     def __init__(self):
10         super().__init__()
11         self.init_ui()
12 
13     def init_ui(self):
14         self.ui = uic.loadUi(r"C:\Users\19225\PycharmProjects\test\src\user\static\login.ui")
15         # 提取要操作的控件
16         self.user_name_qwidget = self.ui.lineEdit  # 用户名输入框
17         self.password_qwidget = self.ui.lineEdit_2  # 密码输入框
18         self.login_btn = self.ui.pushButton  # 登录按钮
19         self.forget_password_btn = self.ui.pushButton_2  # 忘记密码按钮
20         self.textBrowser = self.ui.textBrowser  # 文本显示区域
21         # 绑定信号与槽函数
22         self.login_btn.clicked.connect(self.start_login_task)
23 
24     def start_login_task(self):
25         """启动登录任务的函数,创建一个新线程来执行登录操作"""
26         login_thread = Thread(target=self.login)
27         login_thread.start()
28 
29     def login(self):
30         """登录按钮的槽函数"""
31         user_name = self.user_name_qwidget.text()
32         password = self.password_qwidget.text()
33         for i in range(10):
34             print("正在登录服务器....%d" % (i + 1))
35             time.sleep(1)
36         if user_name == "admin" and password == "123456":
37             self.textBrowser.setText("欢迎%s" % user_name)
38             self.textBrowser.repaint()
39         else:
40             self.textBrowser.setText("用户名或密码错误....请重试")
41             self.textBrowser.repaint()
42 
43 
44 if __name__ == '__main__':
45     app = QApplication(sys.argv)
46     w = MyWindow()
47     # 展示窗口
48     w.ui.show()
49     app.exec()

 

 

posted on 2024-09-04 15:02  认真的六六  阅读(20)  评论(0编辑  收藏  举报