wxPython应用开发-后台线程更新大量数据到wxGrid避免ui无响应

news/2024/7/14 19:36:31/文章来源:https://blog.csdn.net/bahamutj/article/details/139271983

一、问题描述

最近几天,我在用python开发一个数据处理的小工具。需要将xls文件中的大量数据(少则几千行多则几万行)读取出来后进行处理。其中一个功能是需要实现将读取到的原始数据和计算出来的结果在软件界面中以表格形式展示出来。

在python应用开发中,我基本用wxFormBuilder进行软件界面的设计,因此用到wxPython的时候很多。wxPython中的表格类是wx.grid。这次开发过程中遇到的问题是,通过pandas将几万行数据从xls文件中读取到dataframe中后,再更新到软件主界面中的wxGrid中时,由于数据很大,导致软件ui在一段时间内无响应,一直到数据全部写入"时点库存表“中后,才会响应。

(从xls文件读取几万行数据后,向wxGrid加载数据时,出现未响应提示)

本软件中将数据从dataframe对象(self.df_kcb)写入到ui上显示为“时点库存表“的wxGrid对象(self.m_grid_kcb)中的关键代码如下:

# self.m_grid_kcb是wxGrid对象,self.df_kcb是dataframe对象
# 在执行下述代码之前,会首先清空self.m_grid_kcb
# 然后根据self.df_kcb中的数据行数修改self.m_grid_kcb行数,使两者保持一致for x in range(self.grid_kcb_rows):  # self.grid_kcb_rows为表格行数for y in range(6):  # 本软件中为时点库存表为6列self.m_grid_kcb.SetCellValue(x, y, str(self.df_kcb.iloc[x][y]))  # 逐单元格将数据写入wxGrid中

该代码使用了双循环语句,逐个单元格的写入数据,效率不高,在遇到几万行数据时,就导致了ui无响应了。

二、解决办法

我在网上搜索相应的解决办法,找到了如下的一段话。

————————————————————————————————————————

在Python中,将大量数据写入wxPython的wx.grid.Grid控件可能会导致UI响应变慢。为了提高响应性,可以尝试以下方法:

1.分批写入数据:不要一次性将所有数据都加载到wx.grid.Grid中,而是使用分页或滚动机制,每次只加载可见的数据。

2.使用wx.lib.delayedresult:这个模块可以帮助你在一个单独的线程中处理数据的加载,从而不会阻塞UI线程。

3.避免不必要的更新:只有当数据真正改变时才更新wx.grid.Grid,避免不必要的重绘和布局操作。

————————————————————————————————————————

第一个方法,我在去年开发一款软件的时候已经用过了,那款软件中的dataframe对象内的数据量也是有上万行,采用分页显示,每次只显示当前页的几十行数据,通过导航按钮切换页面,没有出现过未响应的情况。但这次我不准备采用这个方法,因为走重复的路是无法学到新知识的。

第二个方法,在那段话后面确实附带了相关的代码示例,但是我尝试将示例融合到我的代码中,确没有成功,总是出现错误。

第三个方法嘛,则不适合当前的应用场景。因为我的应用每次都会选择加载不同的数据,数据量也不一样,必然会对wxGrid中的所有内容都进行更新。

我仍然坚持在一个页面内显示所有的数据,那么就必须解决ui无响应的问题。再次搜索的时候,我使用了“python 如何实现在后台线程中将大量数据写入wxGrid”的关键字起到了作用,百度AI给了我一个有效的答案。

这个答案中的示例直接进行测试是有效的,在想wxGrid加载数据过程中,ui界面不会出现未响应的情况。

(直接运行后,界面有响应,往下拖可以看到数据还没有更新完)

(拖动滑动条的过程中,可以看到数据在更新)

这个代码的关键是用threading模块创建后台线程,并在线程中使用wxCallAfter方法更新wxGrid。

为了实现后台线程操作,要创建一个类:

class WorkerThread(threading.Thread):""" 后台线程向wxGrid加载数据 """def __init__(self, grid, df, rows, cols):threading.Thread.__init__(self)self.grid = gridself.df = dfself.rows = rowsself.cols = colsdef run(self):for row in range(self.rows):for col in range(self.cols):wx.CallAfter(self.grid.SetCellValue, row, col, str(self.df.iloc[row][col]))

然后在我的主程序中,将之前的更新wxGrid的双循环语句替换成以下的代码:

self.worker = WorkerThread(self.m_grid_kcb, self.df_kcb, self.grid_kcb_rows, 6)  # 后台线程更新到grid
self.worker.start()

我参照示例修改了自己的软件,让更新wxGrid的操作在后台线程中执行,就解决了ui未响应的问题了。效果如下:

(没有出现未响应的情况,可以拖动滑条到底,表格的行数已更新,但数据还没有更新完)

(数据更新完的情况,在更新过程中,可以拖动滑条查看数据更新情况)

三、百度AI给的答案和代码

我在百度ai搜索到的文字内容和示例代码如下(代码中我添加了一点标注):

在Python中,你可以使用threading模块来创建后台线程,并在该线程中更新wxPython界面中的wxGrid。为了安全地在不同的线程之间更新GUI,你需要使用wxPython提供的wx.CallAfter方法。

以下是一个简单的例子,展示如何在后台线程中将大量数据写入wxGrid:

import wx
import wx.grid
import threading
import timeclass MyFrame(wx.Frame):def __init__(self, parent):wx.Frame.__init__(self, parent, -1, "wxGrid Example")self.grid = wx.grid.Grid(self)# 创建并设置表格self.grid.CreateGrid(100, 2)  # 100行2列self.grid.SetRowLabelSize(-1)self.grid.SetColLabelSize(-1)# 创建并启动后台线程(这两行代码代替我之前写的双循环语句)self.worker = WorkerThread(self.grid)self.worker.start()# 这个类可以直接复制到自己的代码中后根据情况进行修改
class WorkerThread(threading.Thread):def __init__(self, grid):threading.Thread.__init__(self)self.grid = griddef run(self):# 模拟数据生成(这行代码,实际应用要替换成实际要写入wxGrid中的数据)data = [(i, i * 2) for i in range(100)]# 将数据写入wxGrid表格中(range方法中的行数和列数,按实际应用修改)for row in range(len(data)):for col in range(2):wx.CallAfter(self.grid.SetCellValue, row, col, str(data[row][col]))# 模拟耗时操作(这行代码,在实际应用中要删除)time.sleep(0.1)def main():app = wx.App(False)frame = MyFrame(None)frame.Show(True)app.MainLoop()if __name__ == '__main__':main()

在这个例子中,WorkerThread类是一个后台线程,它负责生成和处理数据。在MyFrame类的初始化方法中,创建了一个wx.grid.Grid对象,并启动了WorkerThread

WorkerThreadrun方法中,我们通过双层循环模拟了将数据填充到wxGrid中的过程。每设置完一个单元格的值后,我们使用wx.CallAfter来确保在GUI线程中执行这个更新。这样可以避免在后台线程中直接更新GUI,从而避免潜在的线程安全问题。

请注意,这个例子中的time.sleep(0.1)是模拟耗时操作,实际应用中应该去掉或替换为实际的计算或IO操作。此外,根据实际情况,你可能需要更复杂的同步机制,例如使用事件或其他同步原语来通知主线程更新GUI。

希望以上的内容,对大家有用。

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

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

相关文章

【哈希】闭散列的线性探测和开散列的哈希桶解决哈希冲突(C++两种方法模拟实现哈希表)(2)

🎉博主首页: 有趣的中国人 🎉专栏首页: C进阶 🎉其它专栏: C初阶 | Linux | 初阶数据结构 小伙伴们大家好,本片文章将会讲解 哈希函数与哈希 之 哈希桶解决哈希冲突 的相关内容。 如果看到最后…

如何使用宝塔面板搭建Tipask问答社区网站并发布公网远程访问

文章目录 前言1.Tipask网站搭建1.1 Tipask网站下载和安装1.2 Tipask网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道(云端设置)2.3 Cpolar稳定隧道(本地设置) 3. 公网访问测试4.结语 前…

AI联想扩图解决方案,智能联想,无需人工干预

对于众多企业而言,无论是广告宣传、产品展示还是客户体验,高质量、宽广视野的图像都是不可或缺的。受限于车载摄像头等设备的物理限制,我们往往难以捕捉到完整、宽广的视觉场景。针对这一挑战,美摄科技凭借其前沿的AI联想扩图解决…

linux父进程fork出子进程后,子进程为何首先需要close文件描述符。

在linux c/c编程时,父进程fork出子进程后,子进程经常第一件事就是close掉所有的文件描述符;为何需要这样做,本文用一个例子进行简单说明。 考虑到一种情况,父进程创建了tcp服务端套接字,并且listen&#x…

【全开源】招聘求职小程序系统源码(ThinkPHP+原生微信小程序)

基于ThinkPHP和原生微信小程序开发的招聘平台系统,包含微信小程序求职者端、微信小程序企业招聘端、PC企业招聘端、PC管理平台端 构建高效人才交流平台 一、引言:招聘求职市场的数字化趋势 在数字化时代,招聘求职市场也迎来了巨大的变革。…

栈和队列专题(LeetCode)

目录 有效的括号题解代码加解释 用队列实现栈题解代码加解释 设计循环队列题解代码加解释 用栈实现队列题解代码加解释 有效的括号 题解 左括号从s字符串中取出来放入栈中 s中就只有右括号了 那么栈顶的左括号和s的右括号匹配即可 代码中也详细解释了左括号和右括号多少的问题…

【Linux】自己实现一个bash进程

bash就是命令行解释器,就是Linux操作系统让我们看到的,与用户进行交互的一种外壳(shell),当然了bash也是一个进程,它有时候就是通过创建子进程来执行我们输入的命令的。这无疑就离不开我们上篇博客所说的进…

继承详解——C++深度学习解析

前言 : 本节内容是讲解面向对象中三大特性之一的继承。 继承是面向对象程序设计中代码复用的一种重要手段。 通过继承, 我们就可以在原本的代码上进行扩展, 而不是重新写一段代码, 让代码变得冗余。 同时, 继承也体现了…

摸鱼大数据——Hive表操作——复杂类型

1、hvie的SerDe机制 其中ROW FORMAT是语法关键字,DELIMITED和SERDE二选其一。本次我们主要学习DELIMITED关键字相关知识点 如果使用delimited: 表示底层默认使用的Serde类:LazySimpleSerDe类来处理数据。 如果使用serde:表示指定其他的Serde类来处理数据,支持用户自…

破解面试难题:面试经典150题 之双指针法详解与代码实现

面试经典 150 题 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 125. 验证回文串 125. 验证回文串 STL容器 思路: 遍历输入的字符串,将其中的字母字符转换为小写&am…

排序进阶----插入排序,希尔排序

各位看官们好,接下来鄙人想与大家分享的实现被称为六大排序之一的插入排序。其实关于这六大排序在我们最开始就已经接触过了。我们在最开始学习c语言的时候,我们要学习到其中之一的冒泡排序。虽然现在看起来冒泡排序确实是没有太大的实际效果&#xff0c…

【物联网实战项目】STM32C8T6+esp8266/mqtt+dht11+onenet+uniapp

一、实物图 前端uniapp效果图(实现与onenet同步更新数据) 首先要确定接线图和接线顺序: 1、stm32c8t6开发板连接stlinkv2下载线 ST-LINK V2STM323.3V3.3VSWDIOSWIOSWCLKSWCLKGNDGND 2、ch340串口连接底座(注意RXD和TXD的连接方式…

kali下载zsteg和stegpy

1.kali下载zsteg 从 GitHub 上克隆zsteg到kali git clone https://github.com/zed-0xff/zsteg 切换目录 cd zsteg 用于安装名为 zsteg 的 Ruby Gem 包 gem install zsteg 2.kali下载stegpy 下载网站内的stegpy-master压缩包GitCode - 开发者的代码家园 并拉到kali中 切换到s…

【豆伴匠】L1-L12更新完,一站式解决文史积累、阅读、写作难题,弯道超车,寒假必备

合抱之木,生于毫末; 九层之台,起于垒土; 千里之行,始于足下。 豆伴匠是什么? 豆伴匠内容包括:人、文、史、作四个模块,全面覆盖文史知识及读写技巧。 目前,豆伴匠有L…

【MySQL】SQL 基础

文章目录 【 1. SQL 的书写规则 】1.1 大小写规则1.2 常量的表示1.3 注释1.4 HELP 系统帮助 【 2. 常用数据库函数 】2.1 SHOW DATABASES 显示数据库2.2 CREATE DATABASE 创建数据库2.3 ALTER DATABASE 修改数据库2.4 DROP DATABASE 删除数据库2.5 USE 选择数据库 【 3. RDBMS …

PyTorch张量索引用法速查

作为数据科学家或软件工程师,你可能经常处理大型数据集和复杂的数学运算,这些运算需要高效且可扩展的计算。PyTorch 是一个流行的开源机器学习库,它通过 GPU 加速提供快速灵活的张量计算。在本文中,我们将深入研究 PyTorch 张量索…

【架构-19】架构风格比较

独立构件风格(Independent Components): 适用场景:需要灵活扩展和组合的复杂大数据应用 特点: 高度解耦:各组件之间高度独立,可单独开发和部署 灵活性和可扩展性:易于根据需求添加或替换组件 复杂度高:需要管理多个独立的组件及其交互 通信开销:组件间需要通过网络通信,可能会…

深入探索C++继承机制:从概念到实践的全面指南

目录 继承的概念及定义 继承的概念 继承的定义 定义格式 继承方式和访问限定符 继承基类成员访问方式的变化 默认继承方式 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 继承与友元 继承与静态成员 继承的方式 菱形虚拟继承 菱形虚拟继承原理 继承…

超详细的前后端实战项目(Spring系列加上vue3)前端篇+后端篇(三)(一步步实现+源码)

好了,兄弟们,继昨天的项目之后,开始继续敲前端代码,完成前端部分(今天应该能把前端大概完成开启后端部分了) 昨天补充了一下登录界面加上了文章管理界面和用户个人中心界面 完善用户个人中心界面 修改一…

华为设备WLAN配置之AP上线

WLAN基础配置之AP上线 配置WLAN无线网络的第一阶段,AP上线技术: 实验目标:使得AP能够获得来自AC的DHCP地址服务的地址,且是该网段地址池中的IP。 实验步骤: 1.把AC当作三层交换机配置虚拟网关 sys Enter system view,…