目录
专栏导读
专栏订阅地址:https://blog.csdn.net/qq_35831906/category_12375510.html
4 数据库操作
4.1 连接数据库
使用 Qt 的 QSqlDatabase 类可以连接到数据库。以下是一个简单的示例:
from PyQt6.QtSql import QSqlDatabase
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("my_database.db")
if db.open():
print("Connected to database")
else:
print("Failed to connect")
4.2 执行 SQL 查询和更新:
你可以使用 QSqlQuery 类来执行 SQL 查询和更新操作。以下是一个示例:
from PyQt6.QtSql import QSqlQuery
query = QSqlQuery()
query.exec("SELECT * FROM employees")
while query.next():
name = query.value("name")
print("Employee name:", name)
4.3 使用模型和视图显示数据
Qt 提供了模型-视图架构来显示数据库中的数据。例如,可以使用 QSqlTableModel 来在 QTableView 中显示数据。以下是一个示例:
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView, QVBoxLayout, QWidget, QPushButton, QLineEdit, QDockWidget
from PyQt6.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery
from PyQt6.QtCore import Qt
class AddDataDialog(QWidget):
def __init__(self, model):
super().__init__()
self.model = model
layout = QVBoxLayout()
self.setLayout(layout)
# 添加姓名输入框
self.name_input = QLineEdit(self)
layout.addWidget(self.name_input)
# 添加职位输入框
self.position_input = QLineEdit(self)
layout.addWidget(self.position_input)
# 添加 "Add Data" 按钮,并连接到添加数据函数
add_button = QPushButton("Add Data", self)
add_button.clicked.connect(self.add_data)
layout.addWidget(add_button)
def add_data(self):
# 获取姓名和职位输入框的内容
name = self.name_input.text()
position = self.position_input.text()
# 准备插入数据的SQL查询
query = QSqlQuery()
query.prepare("INSERT INTO employees (name, position) VALUES (?, ?)")
query.bindValue(0, name)
query.bindValue(1, position)
if query.exec():
print("Data added successfully")
self.model.select() # 刷新表格数据
else:
print("Error adding data:", query.lastError().text())
def create_database_connection():
# 创建数据库连接
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("employees.db")
if not db.open():
print("Error: Could not open database.")
return None
return db
def create_table(db):
# 创建表格的SQL查询
query = QSqlQuery()
query.exec("CREATE TABLE IF NOT EXISTS employees (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, position TEXT)")
def setup_model(db):
# 设置数据库表格模型
model = QSqlTableModel()
model.setTable("employees")
model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit) # 手动提交更改
model.select()
return model
if __name__ == "__main__":
app = QApplication(sys.argv)
db = create_database_connection()
if not db:
sys.exit(1)
create_table(db)
model = setup_model(db)
view = QTableView()
view.setModel(model)
add_data_dialog = AddDataDialog(model)
window = QMainWindow()
window.setWindowTitle("Database Table Example")
window.setCentralWidget(view)
window.setGeometry(100, 100, 800, 600)
add_data_button = QPushButton("Add Data", window)
add_data_button.clicked.connect(add_data_dialog.show)
# 创建 DockWidget 并添加到主窗口的右侧停靠区
dock_widget = QDockWidget("Add Data", window)
dock_widget.setWidget(add_data_dialog)
window.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, dock_widget)
window.show()
sys.exit(app.exec())
5 多线程编程
5.1 多线程编程的概念和优势
5.2 在 PyQt 中使用多线程
在 PyQt 中,你可以使用 QThread 类来创建和管理线程。以下是一个示例,演示如何在一个线程中执行一个耗时的任务:
from PyQt6.QtCore import QThread, pyqtSignal
class WorkerThread(QThread):
result_ready = pyqtSignal(str)
def run(self):
# 执行耗时任务
result = "Task result"
self.result_ready.emit(result)
thread = WorkerThread()
thread.result_ready.connect(lambda result: print("Result:", result))
thread.start()
5.3 处理多线程间的同步和通信问题
在多线程编程中,处理线程间的同步和通信问题是至关重要的,以确保数据的一致性和应用程序的稳定性。PyQt 提供了一些机制来帮助解决这些问题,其中最重要的是信号槽机制和线程安全的数据访问。
5.3.1 信号槽机制
信号槽机制是 PyQt 中用于线程间通信的重要工具。它允许一个对象(信号的发出者)发出信号,而另一个对象(槽函数的接收者)将信号连接到槽函数,从而在信号触发时执行相应的操作。这在多线程环境下特别有用,因为它避免了直接的线程间共享数据。
以下是一个简单的示例,演示如何在多线程中使用信号槽机制:
import sys
from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
class WorkerThread(QThread):
result_ready = pyqtSignal(str)
def run(self):
result = "Task result"
self.result_ready.emit(result)
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Thread Communication Example")
self.setGeometry(100, 100, 400, 300)
self.button = QPushButton("Start Task", self)
self.button.setGeometry(150, 150, 100, 30)
self.button.clicked.connect(self.start_thread)
def start_thread(self):
self.thread = WorkerThread()
self.thread.result_ready.connect(self.handle_result)
self.thread.start()
def handle_result(self, result):
print("Result:", result)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec())
5.3.2 线程安全的数据访问
当多个线程同时访问共享数据时,很容易出现竞争条件和数据不一致的问题。为了避免这些问题,你需要使用互斥锁(mutex)来保护共享数据的访问。PyQt 中的 QMutex 和 QMutexLocker 可以帮助你实现线程安全的数据访问。
以下是一个简单的示例,演示如何在多线程中安全地访问共享数据:
import sys
from PyQt6.QtCore import QThread, QMutex, QMutexLocker
class SharedData:
def __init__(self):
self.mutex = QMutex() # 用于保护共享数据的互斥锁
self.data = 0
def increment(self):
locker = QMutexLocker(self.mutex) # 加锁
self.data += 1
class WorkerThread(QThread):
def __init__(self, shared_data):
super().__init__()
self.shared_data = shared_data
def run(self):
for _ in range(10):
self.shared_data.increment()
if __name__ == "__main__":
shared_data = SharedData() # 创建共享数据对象
threads = [WorkerThread(shared_data) for _ in range(4)] # 创建多个工作线程
for thread in threads:
thread.start() # 启动工作线程
for thread in threads:
thread.wait() # 等待所有工作线程完成
print("Shared data:", shared_data.data) # 打印最终共享数据的值
输出:
5.4 避免死锁和线程饥饿
避免死锁和线程饥饿是多线程编程中的关键问题。死锁指的是多个线程彼此等待对方释放锁,导致程序无法继续执行。线程饥饿是指某个线程长时间无法获得所需的资源或锁,导致其他线程占用资源,使得该线程无法继续执行。以下是在PyQt6中避免死锁和线程饥饿的详解和示例:
以下是一个简单的示例,展示如何在PyQt6中使用QMutex来避免死锁和线程饥饿:
import sys
from PyQt6.QtCore import QThread, QMutex, QMutexLocker
# 共享资源类,用于展示互斥锁的使用来避免死锁和线程饥饿
class SharedResource:
def __init__(self):
self.mutex1 = QMutex() # 第一个互斥锁
self.mutex2 = QMutex() # 第二个互斥锁
def process1(self):
with QMutexLocker(self.mutex1): # 获取第一个锁
print("Process 1: Mutex 1 locked")
QThread.msleep(100) # 模拟处理时间
with QMutexLocker(self.mutex2): # 获取第二个锁
print("Process 1: Mutex 2 locked")
def process2(self):
with QMutexLocker(self.mutex2): # 获取第二个锁
print("Process 2: Mutex 2 locked")
QThread.msleep(100) # 模拟处理时间
with QMutexLocker(self.mutex1): # 获取第一个锁
print("Process 2: Mutex 1 locked")
class WorkerThread(QThread):
def __init__(self, shared_resource, process_func):
super().__init__()
self.shared_resource = shared_resource
self.process_func = process_func
def run(self):
self.process_func()
if __name__ == "__main__":
shared_resource = SharedResource()
thread1 = WorkerThread(shared_resource, shared_resource.process1)
thread2 = WorkerThread(shared_resource, shared_resource.process2)
thread1.start() # 启动线程1
thread2.start() # 启动线程2
thread1.wait() # 等待线程1完成
thread2.wait() # 等待线程2完成
print("Main thread exited") # 主线程退出
QMutex
和 QMutexLocker
QMutex(互斥锁): 互斥锁是一种线程同步机制,用于控制多个线程对共享资源的访问。在多线程环境中,一个线程可以获得互斥锁的所有权,从而可以安全地访问共享资源。其他线程在获取互斥锁之前必须等待,以确保同一时间只有一个线程可以访问共享资源。
示例代码:
from PyQt6.QtCore import QMutex
mutex = QMutex()
def thread_function():
mutex.lock()
# 访问共享资源
mutex.unlock()
# 创建多个线程,每个线程执行 thread_function
QMutexLocker(互斥锁锁定器): QMutexLocker
是 QMutex
的一个辅助类,它在创建时自动锁定 QMutex
,并在销毁时释放锁。这样可以确保在一个作用域内,线程在获取锁后能够正确地释放锁,从而避免忘记释放锁而导致的死锁。
示例代码:
from PyQt6.QtCore import QMutex, QMutexLocker
mutex = QMutex()
def thread_function():
with QMutexLocker(mutex): # 进入作用域时自动锁定,离开作用域时自动释放
# 访问共享资源
# 创建多个线程,每个线程执行 thread_function