如何在显示大量文本时加快滚动响应速度
Posted
技术标签:
【中文标题】如何在显示大量文本时加快滚动响应速度【英文标题】:How to speed up scrolling responsiveness when displaying lots of text 【发布时间】:2016-12-09 17:25:15 【问题描述】:我正在尝试创建一个 Python 脚本来突出显示 .txt 文件中的特定模式。为此,我修改了一个使用 Tkinter 突出显示给定数据集的脚本。但是,我倾向于让它处理的文件大约是 10000 行,这导致滚动缓慢,因为我认为它渲染了所有内容 - 无论它是否在屏幕上(如果我是,请纠正我错误的)。是否可以更改我的代码,使其以更有效的方式呈现输出?我已经尝试寻找一种方法来做到这一点,但我自己没有找到任何东西。
我的代码如下:
from Tkinter import *
class FullScreenApp(object):
def __init__(self, master, **kwargs):
self.master=master
pad=3
self._geom='200x200+0+0'
master.geometry("0x1+0+0".format(
master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))
master.bind('<Escape>',self.toggle_geom)
def toggle_geom(self,event):
geom=self.master.winfo_geometry()
print(geom,self._geom)
self.master.geometry(self._geom)
self._geom=geom
root = Tk()
app = FullScreenApp(root)
t = Text(root)
t.pack()
#Import file
with open('data.txt') as f:
for line in f:
t.insert(END, line)
#Search terms - Leave blank if not required
search_term0 = '0xCAFE'
search_term1 = '0x0011'
search_term2 = '0x961E'
search_term3 = '0x0000'
search_term4 = ''
#Assigns highlighted colours for terms not blank
t.tag_config(search_term0, background='red')
if search_term1 != '':
t.tag_config(search_term1, background='red')
if search_term2 != '':
t.tag_config(search_term2, background='red')
if search_term3 != '':
t.tag_config(search_term3, background='red')
if search_term4 != '':
t.tag_config(search_term4, background='red')
#Define search
#Requires text widget, the keyword, and a tag
def search(text_widget, keyword, tag):
pos = '1.0'
while True:
idx = text_widget.search(keyword, pos, END)
if not idx:
break
pos = '+c'.format(idx, len(keyword))
text_widget.tag_add(tag, idx, pos)
#Search for terms that are not blank
search(t, search_term0, search_term0)
if search_term1 != '':
search(t, search_term1, search_term1)
if search_term2 != '':
search(t, search_term2, search_term2)
if search_term3 != '':
search(t, search_term3, search_term3)
if search_term4 != '':
search(t, search_term4, search_term3)
root.mainloop()
以下链接中给出了文件中的数据示例:here
非常感谢您的宝贵时间,非常感谢。
【问题讨论】:
我已更改问题的标题以反映您想要修复的内容,而不是您认为需要修复的内容。主要是因为我认为情况会相反:我认为渲染所有内容会在第一次显示时变得非常慢,但滚动速度非常快(因为它已经完成了所有渲染)但必须重新渲染每个它滚动的时间会减慢它的速度。 您的代码中的某些缩进被破坏了。 “按住时,它可能会减慢到每秒 2 或 3 行” - 只有您在问题中发布的 exact 代码?另外,文件中的每一行都长吗?我每秒可能会收到 40-50 行。 我怀疑你有一些操作系统设置限制了这一点 - 你可以用鼠标滚轮更快地滚动吗? 我拿了一个quick screencap 我的滚动。我开始用鼠标滚轮滚动,但后来我改为用箭头键滚动。 【参考方案1】:假设 MCVE 如下:
import tkinter as tk
def create_text(text_len):
_text = list()
for _ in range(text_len):
_text.append("\n".format(_))
_text = "".join(_text)
return _text
if __name__ == '__main__':
root = tk.Tk()
txt = tk.Text(root)
txt.text = create_text(10000)
txt.insert('end', txt.text)
txt.pack()
root.mainloop()
分析
基于this 我认为这不是渲染问题。我认为拥有fixed rate of registering <KeyPress>
events 是个问题。这意味着每秒注册的事件数量是固定的,即使硬件可能能够以更快的速度注册。类似的规则也应该适用于鼠标滚动事件。
渲染解决方案
也许为txt['height']
的缓冲区比例分割文本会有所帮助。但这不就是 Tk 应该呈现的方式吗?
渲染无关问题的解决方案
如果一个步骤将被定义为光标移动到上一行或下一行,对于每个注册的 Up 或 Down 事件;然后scrolling_speed = step * event_register_frequency
。
通过增加步长
一个简单的解决方法是为键绑定的每个注册增加步长,例如增加要跳转的行数。
但是已经有这样的默认行为,假设页面长度> 1行,Page Up或Page Down具有页面的步长。这使得滚动速度增加,即使事件注册率保持不变。
或者,可以定义一个具有更大步长的新事件处理程序,为 Up 和 Down 的每次注册调用多个光标移动,例如:
import tkinter as tk
def create_text(text_len):
_text = list()
for _ in range(text_len):
_text.append("\n".format(_))
_text = "".join(_text)
return _text
def step(event):
if txt._step_size != 1:
_no_of_lines_to_jump = txt._step_size
if event.keysym == 'Up':
_no_of_lines_to_jump *= -1
_position = root.tk.call('tk::TextUpDownLine', txt, _no_of_lines_to_jump)
root.tk.call('tk::TextSetCursor', txt, _position)
return "break"
if __name__ == '__main__':
root = tk.Tk()
txt = tk.Text(root)
txt.text = create_text(10000)
txt.insert('end', txt.text)
txt._step_size = 12
txt.bind("<Up>", step)
txt.bind("<Down>", step)
txt.pack()
root.mainloop()
通过模仿按键事件注册表率增加:
正如here 中提到的,实际上修改按键注册表速率超出了 Tk 的范围。相反,它可以被模仿:
import tkinter as tk
def create_text(text_len):
_text = list()
for _ in range(text_len):
_text.append("\n".format(_))
_text = "".join(_text)
return _text
def step_up(*event):
_position = root.tk.call('tk::TextUpDownLine', txt, -1)
root.tk.call('tk::TextSetCursor', txt, _position)
if txt._repeat_on:
root.after(txt._repeat_freq, step_up)
return "break"
def step_down(*event):
_position = root.tk.call('tk::TextUpDownLine', txt, 1)
root.tk.call('tk::TextSetCursor', txt, _position)
if txt._repeat_on:
root.after(txt._repeat_freq, step_down)
return "break"
def stop(*event):
if txt._repeat_on:
txt._repeat_on = False
root.after(txt._repeat_freq + 1, stop)
else:
txt._repeat_on = True
if __name__ == '__main__':
root = tk.Tk()
txt = tk.Text(root)
txt.text = create_text(10000)
txt.insert('end', txt.text)
txt._repeat_freq = 100
txt._repeat_on = True
txt.bind("<KeyPress-Up>", step_up)
txt.bind("<KeyRelease-Up>", stop)
txt.bind("<KeyPress-Down>", step_down)
txt.bind("<KeyRelease-Down>", stop)
txt.pack()
root.mainloop()
通过增加步长和模仿注册率增加
import tkinter as tk
def create_text(text_len):
_text = list()
for _ in range(text_len):
_text.append("\n".format(_))
_text = "".join(_text)
return _text
def step_up(*event):
_no_of_lines_to_jump = -txt._step_size
_position = root.tk.call('tk::TextUpDownLine', txt, _no_of_lines_to_jump)
root.tk.call('tk::TextSetCursor', txt, _position)
if txt._repeat_on:
root.after(txt._repeat_freq, step_up)
return "break"
def step_down(*event):
_no_of_lines_to_jump = txt._step_size
_position = root.tk.call('tk::TextUpDownLine', txt, _no_of_lines_to_jump)
root.tk.call('tk::TextSetCursor', txt, _position)
if txt._repeat_on:
root.after(txt._repeat_freq, step_down)
return "break"
def stop(*event):
if txt._repeat_on:
txt._repeat_on = False
root.after(txt._repeat_freq + 1, stop)
else:
txt._repeat_on = True
if __name__ == '__main__':
root = tk.Tk()
txt = tk.Text(root)
txt.text = create_text(10000)
txt.insert('end', txt.text)
txt._step_size = 1
txt._repeat_freq = 100
txt._repeat_on = True
txt.bind("<KeyPress-Up>", step_up)
txt.bind("<KeyRelease-Up>", stop)
txt.bind("<KeyPress-Down>", step_down)
txt.bind("<KeyRelease-Down>", stop)
txt.pack()
root.mainloop()
【讨论】:
它说我可以在 1 小时内提供赏金【参考方案2】:所以这可以通过称为多线程的东西来解决。一台计算机可以同时执行多项任务,否则您的网络体验将不一样。这是一个演示多线程的简单函数
from threading import Thread
def execOnDifferentThread(funct=print, params=("hello world",)):
t = Thread(target=funct, args=params)
t.start()
现在请注意,这可能不是最好的示例,但现在要并行运行一个函数,您所要做的就是 execOnDifferentThread(funct=A, params=B)
其中 A 是函数名称,B 是 元组 将传递给您的函数的参数。现在,我不想为您编写代码,但是使用此功能,您可以multi-thread
代码的某些部分以使其更快。如果您真的被卡住了,只需评论在哪里并提供帮助。但是请先自己尝试,现在您已经掌握了多线程的能力
【讨论】:
另外,记住在多线程中使用全局变量时,将它们声明为全局变量 我建议线程化代码的t.insert
和search
部分以上是关于如何在显示大量文本时加快滚动响应速度的主要内容,如果未能解决你的问题,请参考以下文章
使用鼠标滚轮时如何加快 JScrollPane 中的滚动速度?
如何加快 UIScrollView 中的滚动速度? [关闭]
当用户向下滚动时,我可以动态更改网站的滚动速度以加快速度吗?