具体来说,我输出一系列结果,随着输出行数增加,能够自动随着输出不断滚动到最新。但是当我需要查看之前的输出结果时(此时输出还在进行中),能够往上查看,当我把滚轮或者进度条滚动到最低点时,自动滚动又重新激活。
以下是多次问了 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()
1
EngAPI 362 天前
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_queue.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 的,你看看能运行么? |
2
sungo OP 应该不行,我回头试试看。chatgpt3.5 问了几次,要不能自动滚,要不滚不了。不知道 4.0 的能不能行
|
3
NoOneNoBody 362 天前
为何不把最新放在前面?
看你的需求,新>旧,难度时间正序排列是强需求? tkinter 我很少写,pyqt 的话 这里有两个状态,自动滚动和手动滚动,你需要一个状态方式(例如状态机或状态判断)控制两者切换,触发事件是什么,例如 mouse down+mouse up ,以及手动滚动时的事件,所以至少需要三个事件响应函数,以及一个自动滚动函数 |
4
sungo OP 倒序排列也可以。之所以正序排列是直接让 poe 把输出转换成 gui 的,也没想到那么多。其实这些都不是啥必须的需求,只是想解决这个常见的问题。
|
5
nerkeler 361 天前 via Android
每次写入绑定滚动拦,默认滚动到最后一列?
|
7
sungo OP 最后解决了问题,两个方案,一是用 pyqt5 ,设置文本框只读,自动就达成目的。
|
8
sungo OP 方案二
```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() ``` |