Reputation: 3863
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
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