I am using Tkinter to visualize sensor data. I have serial data being read, and I want to use it to move a square on the screen.
from tkinter import Tk, Canvas
import tkinter
import serial
#GUI
root = Tk()
c = Canvas(root, width=1000, height=50)
c.configure(bg='grey', highlightthickness=0)
#Position Parameters
posX=10
posY=20
lenght=10
subject = c.create_rectangle(posX, posY, posX lenght, posY lenght, outline='black', fill='black')
#Serial Data Read
ser = serial.Serial('COM5', baudrate=9600, timeout=0.2) # open serial port
print(ser.name) # check which port was really used
#Failed Live Visual
while True:
while (ser.inWaiting()==0):
pass
dataPacket=ser.readline()
dataPacket=str(dataPacket, 'utf-8') #Incoming data from arduino into string
dataPacket=int(dataPacket.strip(' \r\n')) #Formatting
posX=dataPacket
c.coords(subject, posX, posY, posX lenght, posY lenght)
c.pack()
root.mainloop()
My issue is: that Tkinter will display but not update the position of the square. I've tried different approaches such as using the c.move() setter, as well as creating a function and calling it with the root.after() command but none seem to work. I don't think this should be so difficult, so that's why I ask.
Thank you for your time!
CodePudding user response:
The way you're using mainloop()
is wrong — it's typically only called once in a tkinter
application because it is the loop that drives the whole GUI which is event-driven.
One way to work around that limitation in this case would be to use its universal after()
widget method to schedule periodic checks of the serial port for input.
I've made changes to your code to do this, including adding a Start button to initiate the periodic polling process. Obviously I couldn't fully test it, but it ought to give you the overall idea.
import tkinter as tk
import serial
#GUI
root = tk.Tk()
start_btn = tk.Button(root, text='Start')
start_btn.pack(anchor=tk.NW)
c = tk.Canvas(root, width=1000, height=50)
c.configure(bg='grey', highlightthickness=0)
c.pack() # ADDED
#Position Parameters
posX=10
posY=20
lenght=10
subject = c.create_rectangle(posX, posY, posX lenght, posY lenght, outline='black', fill='black')
#Serial Data Read
ser = serial.Serial('COM5', baudrate=9600, timeout=0.2)
print(ser.name) # check which port was really used
def check_data():
if ser.inWaiting():
dataPacket=ser.readline()
dataPacket=str(dataPacket, 'utf-8') #Incoming data from arduino into string
dataPacket=int(dataPacket.strip(' \r\n')) #Formatting
posX=dataPacket
c.coords(subject, posX, posY, posX lenght, posY lenght)
root.after(250, check_data) # Check again in 250 ms.
start_btn.config(command=check_data)
root.mainloop()