user1584421
user1584421

Reputation: 3863

Tkinter: autoscroll to the bottom when user is not scrolling

I have made a small tkinter application, that receives data from the serial port and displays them on a ScrolledText frame.

I have manaded to make the frame autoscroll down to the end, when new data appears.

There is a problem however. If the user wants to see a particular value the autoscrolling option will make him lose it. This is why i want to make it autoscroll, only when the user is not scrolling manually.

I based my code on this answer: Python: Scroll a ScrolledText automatically to the end if the user is not scrolling manually

This is my code:

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

However, this is not working. This code just constantly autoscrolls down, regardless of the use is manually scrolling up.

UPDATE: This is the code from the scrolledText frame:

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')

UPDATE 2: Full code

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

Upvotes: 0

Views: 759

Answers (1)

astqx
astqx

Reputation: 2096

yview()[1] does not consistently return 1.0 since your text widget is constantly being updated. Instead of using scrolledtext module you can create one yourself, that way you have a control over the Scrollbar's attributes. Check the below example.

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()

get method of Scrollbar return a tuple of (top,bottom) coordinates accurately and you can make use of this.

Upvotes: 1

Related Questions