如何防止PySimpleGUI Listbox添加新数据时滚动条自动回顶
解决PySimpleGUI Listbox更新时滚动条跳回顶部的问题
你的问题根源在于每次调用window["-NUMBERS-"].update(list_of_numbers)时,Listbox会完全重新渲染整个列表,导致滚动条被强制重置到顶部。下面提供两种直接可行的解决方法:
方法一:仅追加新元素(推荐)
让后台线程只传递新增的单个元素,主窗口用append=True参数将元素添加到Listbox,避免重新渲染整个列表。
修改后的完整代码:
import queue from threading import Thread from time import sleep import PySimpleGUI as sg numbers_queue = queue.Queue() def add_number_to_list(numbers_queue): for i in range(0, 20): sleep(0.5) # 只传递新增的单个数字,而非整个列表 numbers_queue.put(i) layout = [ [sg.Text("Hello from PySimpleGUI")], [sg.Button("Start")], [sg.Listbox(values=[], enable_events=True, size=(40, 10), key="-NUMBERS-")] ] window = sg.Window(title="Hello World", layout=layout, margins=(500, 500)) while True: event, values = window.read(timeout=100) if event == sg.WIN_CLOSED: break if event == "Start": numbers_thread = Thread(target=add_number_to_list, args=(numbers_queue,), daemon=True) numbers_thread.start() try: new_num = numbers_queue.get_nowait() # 使用append=True追加新元素,不触发滚动条重置 window["-NUMBERS-"].update([new_num], append=True) except queue.Empty: pass window.close()
方法二:记录并恢复滚动位置
如果业务场景要求必须全量更新列表(比如列表存在修改、删除操作),可以先获取当前滚动位置,更新后再恢复:
修改主循环中处理列表更新的部分:
try: list_of_numbers = numbers_queue.get_nowait() if list_of_numbers: # 获取当前滚动条位置 listbox_widget = window["-NUMBERS-"].Widget scroll_pos = listbox_widget.yview() # 全量更新列表 window["-NUMBERS-"].update(list_of_numbers) # 恢复之前的滚动位置 listbox_widget.yview_moveto(scroll_pos[0]) except queue.Empty: pass
关键说明:
- 方法一效率更高,适合仅新增元素的场景,从根源上避免滚动条跳动。
- 方法二通过操作底层tkinter组件实现位置保存,适用于需要全量更新列表的复杂场景。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

