【100天精通python】Day38:GUI界面编程_PyQT从入门到实战(中)

目录

  专栏导读 

4 数据库操作

4.1 连接数据库

4.2 执行 SQL 查询和更新:

4.3 使用模型和视图显示数据

 5 多线程编程

5.1 多线程编程的概念和优势

5.2 在 PyQt 中使用多线程

5.3 处理多线程间的同步和通信问题

5.3.1 信号槽机制

5.3.2 线程安全的数据访问

 QMutex 和 QMutexLocker


  专栏导读 

专栏订阅地址:https://blog.csdn.net/qq_35831906/category_12375510.html


4 数据库操作

      

        PyQt6中的数据库操作主要涉及到Qt的SQL模块,该模块提供了用于连接和管理数据库的功能。下面是一个关于PyQt6数据库操作的概述:

  1. 数据库连接: 使用QSqlDatabase类建立与数据库的连接。可以连接到各种数据库引擎,例如SQLite、MySQL、PostgreSQL等。连接需要指定数据库类型、主机、用户名、密码等信息。

  2. 数据库查询: 使用QSqlQuery类执行SQL查询语句,例如SELECT、INSERT、UPDATE等。查询结果可以通过迭代获取。

  3. 模型-视图架构: PyQt6提供了QSqlTableModelQSqlQueryModel等模型类,用于将数据库数据与Qt的视图类(如QTableView)连接起来。这使得在表格视图中展示和编辑数据库中的数据变得更加容易。

  4. 事务管理: 可以使用QSqlDatabase.transaction()QSqlDatabase.commit()来进行数据库事务的管理,确保数据的一致性和完整性。

  5. 数据绑定: 使用bindValue()方法可以将变量绑定到SQL查询,这有助于防止SQL注入攻击。

  6. 错误处理: 数据库操作可能会出现错误,通过检查QSqlQuerylastError()可以获取详细的错误信息。

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 多线程编程的概念和优势

        PyQt6中的多线程编程允许你在应用程序中同时执行多个任务,以提高性能、响应速度和资源利用率。在使用多线程时,你需要注意线程之间的同步和通信,以避免数据竞争和其他并发问题。以下是PyQt6多线程编程的概述:

  1. 线程类(QThread): QThread 是 PyQt6 提供的线程基类,用于创建和管理线程。你可以继承 QThread 并实现 run() 方法来定义线程的执行逻辑。

  2. 线程安全性: 在多线程环境中,多个线程可能同时访问和修改共享资源。确保对共享资源的访问是线程安全的是很重要的,可以使用互斥锁(QMutex)来控制对共享资源的访问。

  3. 信号和槽机制: 在多线程中,通常不能直接在非主线程中更新用户界面。可以使用信号和槽机制,通过在主线程中处理信号来更新界面,从而避免线程间的界面更新问题。

  4. 多线程的应用场景: 多线程在以下情况下特别有用:

    • 执行耗时操作,如文件读写、网络请求等,以避免主线程阻塞。
    • 实现实时数据刷新,如传感器数据、图表数据等。
    • 并发处理多个任务,提高程序的整体性能。
  5. 线程同步和通信: 多线程编程需要考虑线程之间的同步和通信。合适的同步机制(如互斥锁、信号量、条件变量等)和通信机制(如队列、信号槽等)可以确保线程间的正确协作。

  6. 避免死锁和线程饥饿: 死锁和线程饥饿是多线程编程中常见的问题。确保正确地设计和组织线程同步和通信,以避免出现这些问题。

总之,多线程编程可以显著提高应用程序的性能和响应能力,但也需要仔细考虑线程安全性和正确的同步机制。PyQt6提供了一些类和工具来帮助你实现多线程应用程序,但需要小心处理潜在的并发问题。

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)  # 打印最终共享数据的值

输出: 

         在这个示例中,每个工作线程在循环中执行10次的增量操作,使用互斥锁确保在任何时候只有一个线程可以访问和修改SharedData对象的data属性。这样可以避免数据竞争和不一致的情况。

        注意,这个示例使用了Python中的多线程和互斥锁,与Qt中的线程和互斥锁略有不同。确保你的环境中同时存在Qt库和Python的线程支持(例如PyQt6.QtCorethreading库),以便代码可以正确运行。

5.4 避免死锁和线程饥饿

        避免死锁和线程饥饿是多线程编程中的关键问题。死锁指的是多个线程彼此等待对方释放锁,导致程序无法继续执行。线程饥饿是指某个线程长时间无法获得所需的资源或锁,导致其他线程占用资源,使得该线程无法继续执行。以下是在PyQt6中避免死锁和线程饥饿的详解和示例:

避免死锁:

  1. 有序获取锁: 当多个线程需要获取多个锁时,确保它们按照相同的顺序获取锁,这可以减少死锁的风险。

  2. 超时机制: 在获取锁时使用超时机制,如果无法在一定时间内获取锁,就放弃并释放已有的锁。

避免线程饥饿:

  1. 公平性: 使用公平的锁和资源分配策略,确保所有线程都有平等的机会获得资源,避免某个线程长时间无法获得所需资源。

  2. 优先级: 在某些情况下,可以通过为线程设置不同的优先级,确保高优先级线程不会长时间无法获得资源。

以下是一个简单的示例,展示如何在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")  # 主线程退出

         在这个示例中,两个线程分别尝试获取两个不同的锁(mutex1和mutex2)。通过始终以相同的顺序获取锁,可以避免死锁。同时,通过在获取锁时使用QMutexLocker,可以确保线程在离开作用域时释放锁。

        需要注意的是,死锁和线程饥饿是复杂的问题,可能在更复杂的场景中出现。避免死锁和线程饥饿需要仔细的设计和测试,以确保线程在协同工作时能够正确地进行同步和协调。

 QMutexQMutexLocker

QMutexQMutexLocker 是 PyQt 中用于线程同步的两个重要类。它们帮助确保多个线程在访问共享资源时的正确同步,以避免竞争条件和数据不一致。下面是关于它们的详解和示例:

QMutex(互斥锁): 互斥锁是一种线程同步机制,用于控制多个线程对共享资源的访问。在多线程环境中,一个线程可以获得互斥锁的所有权,从而可以安全地访问共享资源。其他线程在获取互斥锁之前必须等待,以确保同一时间只有一个线程可以访问共享资源。

示例代码:

from PyQt6.QtCore import QMutex

mutex = QMutex()

def thread_function():
    mutex.lock()
    # 访问共享资源
    mutex.unlock()

# 创建多个线程,每个线程执行 thread_function

QMutexLocker(互斥锁锁定器): QMutexLockerQMutex 的一个辅助类,它在创建时自动锁定 QMutex,并在销毁时释放锁。这样可以确保在一个作用域内,线程在获取锁后能够正确地释放锁,从而避免忘记释放锁而导致的死锁。

示例代码:

from PyQt6.QtCore import QMutex, QMutexLocker

mutex = QMutex()

def thread_function():
    with QMutexLocker(mutex):  # 进入作用域时自动锁定,离开作用域时自动释放
        # 访问共享资源

# 创建多个线程,每个线程执行 thread_function

        在使用 QMutexLocker 时,当线程离开作用域(例如使用 with 语句),会自动释放锁,无论是否发生异常。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/77461.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++学习手札】一文带你初识C++继承

食用指南:本文在有C基础的情况下食用更佳 🍀本文前置知识: C类 ♈️今日夜电波:napori—Vaundy 1:21 ━━━━━━️💟──────── 3:23 …

车规级半导体分类(汽车芯片介绍)

车规级半导体,也被称为“汽车芯片”,主要应用于车辆控制装置、车载监控系统和车载电子控制装置等领域。这些半导体器件主要分布在车体控制模块上,以及车载信息娱乐系统方面,包括动力传动综合控制系统、主动安全系统和高级辅助驾驶…

谷歌浏览器安装不上【搬代码】

winR 输入regedit 计算机\HKEY_CURRENT_USER\SOFTWARE\Google 然后重新安装谷歌

如何通过本地搭建wamp服务器并实现无公网IP远程访问

文章目录 前言1.Wamp服务器搭建1.1 Wamp下载和安装1.2 Wamp网页测试 2. Cpolar内网穿透的安装和注册2.1 本地网页发布2.2 Cpolar云端设置2.3 Cpolar本地设置 3. 公网访问测试4. 结语 前言 软件技术的发展日新月异,各种能方便我们生活、工作和娱乐的新软件层出不穷&…

编程练习(2)

一.选择题 第一题: 考察转义字符和strlen函数求解字符串长度 进一步在VS中可以智能看出哪些字符是转义字符: 因此本体答案选择B 第二题: 本体较为简单,宏定义了三个数N,M,NUM,N值为2,M值为3,因此NUM值为8,…

uniapp微信小程序区分正式版,开发版,体验版

小程序代码区分是正式版,开发版,还是体验版 通常正式和开发环境需要调用不同域名接口,发布时需要手动更换 或者有些东西不想在正式版显示,只在开发版体验版中显示,也需要去手动隐藏 官方没有明确给出判断环境的方法&a…

pytorch @操作符

今天发现一个操作符 import torch a torch.tensor([[1,2],[2,3],[5,6]]) b torch.tensor([[2,1],[8,5],[3,2]]) c a*b d a b.t() ## [3,2] [2,3] print(*,c) print(,d)结果如下 import torch# Define matrices A torch.randn(3, 4) B torch.randn(4, 5)# Matrix mult…

强化学习:用Python训练一个简单的机器人

一、介绍 强化学习(RL)是一个令人兴奋的研究领域,它使机器能够通过与环境的交互来学习。在这篇博客中,我们将深入到RL的世界,并探索如何使用Python训练一个简单的机器人。在本文结束时,您将对 RL 概念有基本…

多元最短路(Floyd)

是一个基于动态规划的全源最短路算法。它可以高效地求出图上任意两点之间的最短路 时间复杂度 O(n^3) 状态转移方程 f[i][j]min(f[i][j],f[i][k]f[k][j]) 核心代码 void floyd(){for(int k1;k<n;k)for(int i1;i<n;i)for(int j1;j<n;j)s[i][j]min(s[i][j],s[i][k…

ZooKeeper的应用场景(命名服务、分布式协调通知)

3 命名服务 命名服务(NameService)也是分布式系统中比较常见的一类场景&#xff0c;在《Java网络高级编程》一书中提到&#xff0c;命名服务是分布式系统最基本的公共服务之一。在分布式系统中&#xff0c;被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等一这…

7.1 Redis基础

1、Redis概述 Redis是开源的、高性能的key-value数据库&#xff0c;Redis缓存有以下三个特点&#xff1a; Redis支持数据的持久化&#xff0c;可以将内存中的数据保存在磁盘中&#xff0c;重启的时候可以再次加载进行使用。 Redis不仅仅支持简单的key-value类型的数据&#x…

LangChain手记 Memory

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Memory&#xff08;源码可见&#xff09; Memory 使用open ai的API调用GPT都是单次调用&#xff0c;所以模型并不记得之前的对话&#xff0c;多轮对话的实现其实是将前面轮次的对话过程保留&#xff0c;在下次对话…

mysql主从复制搭建(一主一从)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言MySQL复制过程分为三部&#xff1a; 一、准备工作二、配置>主库Master三、配置>从库SlaveSlave_IO_Running: YesSlave_SQL_Running: Yes 四、测试至此&am…

代码随想录算法训练营第四十二天|LeetCode 121,122

目录 LeetCode 121.买卖股票的最佳时机 动态规划五步曲&#xff1a; 1.确定dp[i][j] 的含义 2.找出递推公式 3.初始化dp数组 4.确定遍历方向 5.打印dp数组 LeetCode 122.买卖股票的最佳时间II 动态规划五步曲&#xff1a; 1.确定dp[i][j] 的含义 2.找出递推公式 3.初始化dp数组…

玩转单元测试之gtest

引言 程序开发的时候&#xff0c;往往需要编写一些测试样例来完成功能测试&#xff0c;以保证自己的代码在功能上符合预期&#xff0c;能考虑到一些异常边界问题等等。 gtest快速入门 1.引入gtest # 使用的是1.10版本&#xff0c;其他版本可根据需要选择 git clone -b v1.1…

【QT】 Word模板编辑、转PDF格式

很高兴在雪易的CSDN遇见你 ,给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享基于QT进行Word模板编辑以及Word转PDF的技术,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 目录 …

集成DTM实现跨语言分布式事务V1.0

集成DTM实现跨语言分布式事务V1.0 简介 DTM是一款开源的分布式事务管理器&#xff0c;解决跨数据库、跨服务、跨语言栈更新数据的一致性问题。 通俗一点说&#xff0c;DTM提供跨服务事务能力&#xff0c;一组服务要么全部成功&#xff0c;要么全部回滚&#xff0c;避免只更新…

《Go 语言第一课》课程学习笔记(一)

配好环境&#xff1a;选择一种最适合你的 Go 安装方法 选择 Go 版本 一般情况下&#xff0c;建议采用最新版本。因为 Go 团队发布的 Go 语言稳定版本的平均质量一直是很高的&#xff0c;少有影响使用的重大 bug。可以根据不同实际项目需要或开源社区的情况使用不同的版本。 有…

Redis-分布式锁!

分布式锁&#xff0c;顾名思义&#xff0c;分布式锁就是分布式场景下的锁&#xff0c;比如多台不同机器上的进程&#xff0c;去竞争同一项资源&#xff0c;就是分布式锁。 分布式锁特性 互斥性:锁的目的是获取资源的使用权&#xff0c;所以只让一个竞争者持有锁&#xff0c;这…