【问题标题】:Tkinter: autoscroll to the bottom when user is not scrollingTkinter:当用户不滚动时自动滚动到底部
【发布时间】:2021-05-29 21:52:09
【问题描述】:

我制作了一个小型 tkinter 应用程序,它从串行端口接收数据并将它们显示在 ScrolledText 框架上。

当新数据出现时,我已授权让框架自动滚动到最后。

但是有一个问题。如果用户想看到一个特定的值,自动滚动选项会让他失去它。 这就是为什么我想让它自动滚动,只有当用户不手动滚动时。

我的代码基于这个答案: Python: Scroll a ScrolledText automatically to the end if the user is not scrolling manually

这是我的代码:

def readSerial():
    global val1
    fully_scrolled_down = scrollbar.yview()[1] == 1.0
    ser_bytes = ser.readline()
    ser_bytes = ser_bytes.decode("utf-8")
    val1 = ser_bytes
    scrollbar.insert("end", val1)
    if fully_scrolled_down:
        scrollbar.see("end") #autoscroll to the end of the scrollbar

但是,这不起作用。这段代码只是不断地自动向下滚动,不管使用的是手动向上滚动。

更新:这是来自 scrolledText 框架的代码:

frame2 = tk.Frame(root, bg='#80c1ff') #remove color later
frame2.place(relx=0, rely=0.1, relheight=1, relwidth=1, anchor='nw')

# make a scrollbar
scrollbar = scrolledtext.ScrolledText(frame2)
scrollbar.place(relx=0, rely=0, relheight=0.9, relwidth=1, anchor='nw')

更新 2: 完整代码

import tkinter as tk
import tkinter.ttk as ttk
import serial.tools.list_ports
from tkinter import scrolledtext 
import time
import serial
import threading
import continuous_threading


#to be used on our canvas
HEIGHT = 700
WIDTH = 800

#hardcoded baud rate
baudRate = 9600

ser = serial.Serial('COM16', baudRate)
val1 = 0

def readSerial():
    global val1
    #https://stackoverflow.com/questions/51781247/python-scroll-a-scrolledtext-automatically-to-the-end-if-the-user-is-not-scroll
    fully_scrolled_down = scrollbar.yview()[1] == 1.0 #remove for ayutoscroll when not afafa
    ser_bytes = ser.readline()
    ser_bytes = ser_bytes.decode("utf-8")
    val1 = ser_bytes
    scrollbar.insert("end", val1)
    if fully_scrolled_down: #remove for ayutoscroll when not afafa
        scrollbar.see("end") #autoscroll to the end of the scrollbar


t1 = continuous_threading.PeriodicThread(0.1, readSerial)
#----------------------------------------------------------------------


#--------------------------------------------------------------------------------
# --- main ---
root = tk.Tk() #here we create our tkinter window
root.title("Sensor Interface")


#we use canvas as a placeholder, to get our initial screen size (we have defined HEIGHT and WIDTH)
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()

# --- frame 2 ---
frame2 = tk.Frame(root, bg='#80c1ff') #remove color later
frame2.place(relx=0, rely=0.1, relheight=1, relwidth=1, anchor='nw')

# make a scrollbar
scrollbar = scrolledtext.ScrolledText(frame2)
scrollbar.place(relx=0, rely=0, relheight=0.9, relwidth=1, anchor='nw')
# --- frame 2 ---
#--------------------------------------------------------------------------------





t1.daemon=True
t1.start()

root.mainloop() #here we run our app

【问题讨论】:

  • 你做了什么来调试这个?您是否查看过 scrollbar.yview()[1] 返回的内容,看看它是否始终符合您的预期?
  • 您在名为 scrollbar 的东西上调用 yviewinsertsee -- scrollbar 是滚动条,还是文本小部件?
  • @BryanOakley 感谢您的关注。我更新了我的代码。
  • 请创建一个有效的minimal reproducible example。当我模拟一个应用程序并按原样添加您的 readSerial 函数时,它工作得很好。
  • @BryanOakley 我用完整代码更新了问题。

标签: python-3.x user-interface tkinter


【解决方案1】:

yview()[1] 不会始终返回 1.0,因为您的文本小部件会不断更新。您可以自己创建一个模块,而不是使用scrolledtext 模块,这样您就可以控制Scrollbar 的属性。检查以下示例。

from tkinter import *
import random

def foo():
    val=random.randint(1000,9999)
    label.config(text=val)
    text.insert(END,f"{val}\n")
    if vsb.get()[1]==1.0:
        text.see(END)
    root.after(200,foo)

root=Tk()

label=Label(root)
label.pack()
text_frame=Frame(root)
text_frame.pack()
text=Text(text_frame)
text.pack(side='left')
vsb=Scrollbar(text_frame)
vsb.pack(side='left',fill='y')
text.config(yscrollcommand=vsb.set)
vsb.config(command=text.yview)

foo()

root.mainloop()

Scrollbarget 方法准确返回一个(top,bottom) 坐标的元组,你可以利用它。

【讨论】:

  • 谢谢。但是由于这会大量更改代码,并且我有两个活动问题,每个问题都需要更改代码,所以我会先尝试解决周期性运行错误,然后再跳到这个。
  • 谢谢!您的代码有效。我做了一个小改动,因为很难将滚动条放在底部,以便自动滚动继续(因为滚动条不断向上移动)。因此,如果 vsb.get()[1]==1.0 从这一行开始,我将 1.0 更改为 0.9。一千谢谢!
猜你喜欢
  • 2018-08-21
  • 2014-12-12
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
相关资源
最近更新 更多