python treeview 多线程下表格插入速度慢解决方法

python treeview 多线程下表格插入速度慢解决方法

 

最近用tk得treeview做了个表格来展视数据

输入id,查询接口数据,然后显示数据

按照之前得操作,搜索按钮绑定一个单独得线程进行操作,这样界面不会卡死,毕竟查询网络接口是个耗时操作

大概是这样得代码

from tkinter import ttk
from tkinter import *
import random
import threading
import time

class MyThread(threading.Thread):
    def __init__(self, func, *args):
        super(MyThread, self).__init__()
        self.func = func
        self.args = args
        self.setDaemon(True)
        self.start()  # 在这里开始

    def run(self):
        self.func(*self.args)

def add_row():
#模拟网络请求 time.sleep(3) for i in range(300): treeview.insert('', i, values=( i, random.randint(1,10), random.randint(1,10), random.randint(1,10), random.randint(1,10), random.randint(1,10))) def del_table(): [treeview.delete(item) for item in treeview.get_children()] root = Tk() column_names = [ f'列{x}' for x in range(6)] columns = list('abcdefghijklmnopqrstuvwxyz'[:len(column_names)]) ybar = Scrollbar(root, orient='vertical') treeview = ttk.Treeview(root, height=18, show="headings", columns=columns, yscrollcommand=ybar.set) # 表格 ybar['command'] = treeview.yview ybar.pack(side=RIGHT, fill=BOTH) for num, column in enumerate(columns): treeview.column(column, width=100, anchor='center') treeview.heading(column, text=column_names[num]) treeview.pack(fill=BOTH) newb = ttk.Button(root, text='添加行', width=20, command=lambda: MyThread(add_row, )) newb.pack(fill=BOTH) newb = ttk.Button(root, text='删除表格', width=20, command=del_table) newb.pack(fill=BOTH) root.mainloop() # 进入消息循环

 点击添加行按钮,3秒后可以看出在插入行,300行要插入个10来秒,插入得时候可以看到滚动条滑块再不停得变小

如果不使用线程,按钮直接绑定函数

比如

newb = ttk.Button(root, text='添加行', width=20, command=add_row)

那么在3秒的休眠中,界面会卡死,无法操作
不过插入行却是一瞬间的事情,几乎1秒不到就插入了300多行
网上查了下,说是不建议在多线程里面操作界面,会出现并发操作问题
而且这个也证明了在线程中进行大量界面修改速度是非常慢的

那么这个解决办法就是不在线程中插入表格,再ui的主线程中插入表格,这样就能做到快速插入
使用工具是queue列队,
还有tk中的after方法,TKinter的root下有个after方法, 这个方法是个定时方法,用途是GUI启动后定时执行一个方法,如果我们在被after调用的方法里再次调用这个after方法,
就可以实现一个循环效果,但这个循环不像while那样会阻塞住主线程


完整代码如下

from tkinter import ttk
from tkinter import *
import random
import threading
import time
import queue


table_queue = queue.Queue()

class MyThread(threading.Thread):
    def __init__(self, func, *args):
        super(MyThread, self).__init__()
        self.func = func
        self.args = args
        self.setDaemon(True)
        self.start()  # 在这里开始

    def run(self):
        self.func(*self.args)

def add_row():
    if not table_queue.empty():
        rows = table_queue.get()
        for row in rows:
            treeview.insert('', row[0], values=(
                row[0],
                row[1],
                row[2],
                row[3],
                row[4],
                row[5]))
    root.after(100, add_row) #运行完后再次加入到循环中

def do_add():
    #模拟网络请求耗时操作
    time.sleep(3)
    rows = [
        [x,random.randint(1,10),random.randint(1,10),random.randint(1,10),random.randint(1,10),random.randint(1,10)]
        for x in range(300)
    ]
    table_queue.put(rows)




def del_table():
    [treeview.delete(item) for item in treeview.get_children()]



root = Tk()

root.after(100, add_row) #启动添加表格操作(不会阻塞主线程)

column_names = [ f'列{x}' for x in range(6)]
columns = list('abcdefghijklmnopqrstuvwxyz'[:len(column_names)])

ybar = Scrollbar(root, orient='vertical')

treeview = ttk.Treeview(root, height=18, show="headings", columns=columns, yscrollcommand=ybar.set)  # 表格
ybar['command'] = treeview.yview
ybar.pack(side=RIGHT, fill=BOTH)

for num, column in enumerate(columns):
    treeview.column(column, width=100, anchor='center')
    treeview.heading(column, text=column_names[num])

treeview.pack(fill=BOTH)

newb = ttk.Button(root, text='添加行', width=20, command=lambda: MyThread(do_add, ))
newb.pack(fill=BOTH)

newb = ttk.Button(root, text='删除表格', width=20, command=del_table)
newb.pack(fill=BOTH)

root.mainloop()  # 进入消息循环

  

posted @ 2020-12-09 14:07  darkspr  阅读(781)  评论(0编辑  收藏  举报