Python tkinter 如何实现自动滚动的文本框 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sungo
V2EX    Python

Python tkinter 如何实现自动滚动的文本框

  •  
  •   sungo 2023-12-31 08:05:13 +08:00 2161 次点击
    这是一个创建于 733 天前的主题,其中的信息可能已经有所发展或是发生改变。

    具体来说,我输出一系列结果,随着输出行数增加,能够自动随着输出不断滚动到最新。但是当我需要查看之前的输出结果时(此时输出还在进行中),能够往上查看,当我把滚轮或者进度条滚动到最低点时,自动滚动又重新激活。

    以下是多次问了 poe 后,有点能用的代码。但是还是不能完全实现上面的要求。有高人能指导下吗?

     import tkinter as tk from tkinter import messagebox import threading import queue import time def down(): for i in range(1, 100): output_queue.put(f"Downloading attachment {i}\n") time.sleep(0.3) return def on_download_click(): try: download_thread = threading.Thread(target=down, args=()) download_thread.start() except Exception as e: messagebox.showerror("消息", "该日期段没有附件下载") def update_output_text(): # 检查队列是否有新的输出内容 while not output_queue.empty(): output_text.insert(tk.END, output_queue.get()) # 如果用户没有手动滚动,或者手动滚动到底部,则自动滚动到底部 if not fm_main.manually_scrolled or output_text.yview()[1] == 1.0: output_text.see(tk.END) # 通过调用 after 方法实现定时刷新 fm_main.after(100, update_output_text) def on_scroll(*args): # 判断滚动条是否在底部 scroll_position = scrollbar.get() if scroll_position[1] == 1.0: fm_main.manually_scrolled = False else: fm_main.manually_scrolled = True if __name__ == '__main__': # os.chdir(path) # os.system("ls *.zip |xargs -n1 unzip && rm *.zip") fm_main = tk.Tk() fm_main.title("邮件附件批量下载_v1.0") fm_main.geometry('600x300') fm_main.resizable(0, 0) # 设置窗口 Continuation of the modified code: # 下载按钮 btn1 = tk.Button(fm_main, text="下载", fOnt=("Arial", 13), width=25, height=2, command=on_download_click) btn1.pack() scrollbar = tk.Scrollbar(fm_main) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) output_text = tk.Text(fm_main, fOnt=("Arial", 12), width=60, height=10) output_text.pack(side=tk.LEFT, fill=tk.BOTH) output_text.config(yscrollcommand=scrollbar.set) scrollbar.config(command=output_text.yview) # ... 其他代码 ... # 创建队列对象用于线程间通信 output_queue = queue.Queue() # 启动定时刷新函数 fm_main.after(100, update_output_text) # 设置滚动条手动滚动的回调函数 output_text.bind("<MouseWheel>", on_scroll) output_text.bind("<Button-4>", on_scroll) output_text.bind("<Button-5>", on_scroll) # 标记手动滚动状态的变量 fm_main.manually_scrolled = False fm_main.mainloop() 
    8 条回复    2024-02-01 10:52:33 +08:00
    EngAPI
        1
    EngAPI  
       2023-12-31 14:13:12 +08:00
    import tkinter as tk
    from tkinter import messagebox
    import threading
    import queue
    import time

    def down():
    for i in range(1, 100):
    output_queue.put(f"下载附件 {i}\n")
    time.sleep(0.3)
    return

    def on_download_click():
    try:
    download_thread = threading.Thread(target=down, args=())
    download_thread.start()
    except Exception as e:
    messagebox.showerror("错误", "该日期段没有附件下载")

    def update_output_text():
    while not output_ueue.empty():
    output_text.insert(tk.END, output_queue.get())

    # 检查滚动条是否在底部
    scroll_position = scrollbar.get()
    if not fm_main.manually_scrolled or scroll_position[1] == 1.0:
    output_text.see(tk.END)

    fm_main.after(100, update_output_text)

    def on_scroll(*args):
    # 判断滚动条是否在底部
    scroll_position = scrollbar.get()
    if scroll_position[1] == 1.0:
    fm_main.manually_scrolled = False
    else:
    fm_main.manually_scrolled = True

    if __name__ == '__main__':
    fm_main = tk.Tk()
    fm_main.title("邮件附件批量下载_v1.0")
    fm_main.geometry('600x300')
    fm_main.resizable(0, 0)

    btn1 = tk.Button(fm_main, text="下载", fOnt=("Arial", 13), width=25, height=2, command=on_download_click)
    btn1.pack()

    scrollbar = tk.Scrollbar(fm_main)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    output_text = tk.Text(fm_main, fOnt=("Arial", 12), width=60, height=10)
    output_text.pack(side=tk.LEFT, fill=tk.BOTH)

    output_text.config(yscrollcommand=scrollbar.set)
    scrollbar.config(command=output_text.yview)

    output_queue = queue.Queue()
    fm_main.after(100, update_output_text)

    output_text.bind("<MouseWheel>", on_scroll)
    output_text.bind("<Button-4>", on_scroll)
    output_text.bind("<Button-5>", on_scroll)

    fm_main.manually_scrolled = False

    fm_main.mainloop()

    问的 chatgpt3.5 的,你看看能运行么?
    sungo
        2
    sungo  
    OP
       2023-12-31 14:20:40 +08:00 via Android
    应该不行,我回头试试看。chatgpt3.5 问了几次,要不能自动滚,要不滚不了。不知道 4.0 的能不能行
    NoOneNoBody
        3
    NoOneNoBody  
       2023-12-31 14:42:14 +08:00
    为何不把最新放在前面?
    看你的需求,新>旧,难度时间正序排列是强需求?

    tkinter 我很少写,pyqt 的话
    这里有两个状态,自动滚动和手动滚动,你需要一个状态方式(例如状态机或状态判断)控制两者切换,触发事件是什么,例如 mouse down+mouse up ,以及手动滚动时的事件,所以至少需要三个事件响应函数,以及一个自动滚动函数
    sungo
        4
    sungo  
    OP
       2024-01-01 08:46:25 +08:00 via Android
    倒序排列也可以。之所以正序排列是直接让 poe 把输出转换成 gui 的,也没想到那么多。其实这些都不是啥必须的需求,只是想解决这个常见的问题。
    nerkeler
        5
    nerkeler  
       2024-01-01 11:03:57 +08:00 via Android
    每次写入绑定滚动拦,默认滚动到最后一列?
    sungo
        6
    sungo  
    OP
       2024-01-01 17:46:20 +08:00 via Android
    @nerkeler 输出是从上往下输出的,当然希望不停刷新显示最后一列,也就是最新的输出了
    sungo
        7
    sungo  
    OP
       2024-02-01 10:40:59 +08:00
    最后解决了问题,两个方案,一是用 pyqt5 ,设置文本框只读,自动就达成目的。
    sungo
        8
    sungo  
    OP
       2024-02-01 10:52:33 +08:00
    方案二
    ```python
    import tkinter as tk
    from tkinter import messagebox
    import threading
    import queue
    import time


    def down():
    for i in range(1, 100):
    output_queue.put(f"Downloading attachment {i}\n")
    time.sleep(0.3)
    return


    def on_download_click():
    try:
    download_thread = threading.Thread(target=down, args=())
    download_thread.start()
    except Exception as e:
    messagebox.showerror("消息", "该日期段没有附件下载")


    def update_output_text():
    # 检查队列是否有新的输出内容
    while not output_queue.empty():
    output_text.insert(tk.END, output_queue.get())
    # 如果用户没有手动滚动,或者手动滚动到底部,则自动滚动到底部
    if not fm_main.manually_scrolled or output_text.yview()[1] == 1.0:
    output_text.see(tk.END)

    # 通过调用 after 方法实现定时刷新
    fm_main.after(100, update_output_text)


    def on_scroll(*args):
    # 判断滚动条是否在底部
    scroll_position = scrollbar.get()
    if scroll_position[1] == 1.0:
    fm_main.manually_scrolled = False
    else:
    fm_main.manually_scrolled = True


    def on_mouse_release(*args):
    on_scroll()


    def on_key_press(event):
    if event.keysym in ["Up", "Down", "Left", "Right"]:
    on_scroll()


    if __name__ == "__main__":
    # os.chdir(path)
    # os.system("ls *.zip |xargs -n1 unzip && rm *.zip")

    fm_main = tk.Tk()
    fm_main.title("邮件附件批量下载_v1.0")
    fm_main.geometry("600x300")

    fm_main.resizable(0, 0) # 设置窗口 Continuation of the modified code:

    # 下载按钮
    btn1 = tk.Button(
    fm_main,
    text="下载",
    fOnt=("Arial", 13),
    width=25,
    height=2,
    command=on_download_click,
    )
    btn1.pack()

    scrollbar = tk.Scrollbar(fm_main)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    output_text = tk.Text(fm_main, fOnt=("Arial", 12), width=60, height=10)
    output_text.pack(side=tk.LEFT, fill=tk.BOTH)

    output_text.config(yscrollcommand=scrollbar.set)
    scrollbar.config(command=output_text.yview)

    # ... 其他代码 ...

    # 创建队列对象用于线程间通信
    output_queue = queue.Queue()

    # 启动定时刷新函数
    fm_main.after(100, update_output_text)

    # 设置滚动条手动滚动的回调函数
    output_text.bind("<MouseWheel>", on_scroll)
    output_text.bind("<Button-4>", on_scroll)
    output_text.bind("<Button-5>", on_scroll)

    scrollbar.bind("<MouseWheel>", on_scroll)
    scrollbar.bind("<Button-4>", on_scroll)
    scrollbar.bind("<Button-5>", on_scroll)

    scrollbar.bind("<B1-Motion>", on_scroll)
    scrollbar.bind("<ButtonRelease-1>", on_mouse_release)

    # 方向键事件绑定
    fm_main.bind("<Up>", on_key_press)
    fm_main.bind("<Down>", on_key_press)
    fm_main.bind("<Left>", on_key_press)
    fm_main.bind("<Right>", on_key_press)

    # 标记手动滚动状态的变量
    fm_main.manually_scrolled = False

    fm_main.mainloop()
    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2023 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 00:24 PVG 08:24 LAX 16:24 JFK 19:24
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86