0

I have created this semi-circle which takes values from Arduino(Serial) and then rotates according to those values. The problem is that Tkinter canvas keeps the old circle as well. I canvas to just show me the new one and removes the old one. The code is attached below.

import serial
import time    
from tkinter import *
import math
#-----------------------------------------------
ser = serial.Serial('COM5',baudrate = 9600)
ser.flushInput()
#-----------------------------------------------   
def tilt():
    ser_bytes = int(ser.readline().decode('ascii'))
    adata = (ser.readline().strip())
    ser_bytes = str(adata.decode('utf-8'))
    angle = int(ser_bytes)-247
    arc = c.create_arc(50, 50, 200, 200,start =angle,extent=-180, fill="red")
    c.delete(arc)
    root.after(100,tilt)
    print('X: {}' .format(ser_bytes))

root = Tk()
root.title("Control Panel")
root.geometry('1200x750')
frame_1 = Frame(root)
frame_1.pack()
c = Canvas(frame_1,width = 1000, height = 1000, bg = '#5F9EA0')
c.pack()
tilt()    
root.mainloop()
cassini
  • 21
  • 1
  • 4
  • When I use 'c.delete' then nothing is shown in canvas – cassini Feb 28 '20 at 15:41
  • 1
    Are you aware of the documented `itemconfigure` method? – Bryan Oakley Feb 28 '20 at 15:42
  • Why reading from the serial port twice? The first `ser_bytes = int(ser.readline().decode('ascii')` seems not necessary as `ser_bytes` will be overwritten by second reading. – acw1668 Feb 28 '20 at 16:07
  • @SyedImtiazAliShah ***"When I use 'c.delete'"***: Read up on [Tkinter.Canvas.itemconfig-method](http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas.itemconfig-method). Relevant: [how-to-create-zigzag-movements-in-python](https://stackoverflow.com/questions/24282937) and [update the screen (canvas)](https://stackoverflow.com/a/7918667/7414759) – stovfl Feb 28 '20 at 16:24
  • @acw1668 Yes, it is unnecessary. But the problem still persists. – cassini Feb 28 '20 at 17:36
  • 1
    @BryanOakley it worked – cassini Feb 28 '20 at 17:58

2 Answers2

0

You should create the arc once when program starts and then use canvas.itemconfig() to change its start angle:

import serial
from tkinter import *
#-----------------------------------------------
ser = serial.Serial('COM5', baudrate=9600)
ser.flushInput()
#-----------------------------------------------
def con():
    ser_bytes = int(ser.readline().decode('ascii'))
    return ser_bytes

def tilt():
    angle = con()
    c.itemconfig(arc, start=angle)
    root.after(100, tilt)
    print('X: {}'.format(angle))

root = Tk()
root.title("Control Panel")
root.geometry('1200x750')
frame_1 = Frame(root)
frame_1.pack()
c = Canvas(frame_1, width=1000, height=1000, bg='#5F9EA0')
c.pack()
# create the arc
arc = c.create_arc(50, 50, 200, 200, start=0, extent=-180, fill="red")
# start updating the arc
tilt()    
root.mainloop()
acw1668
  • 40,144
  • 5
  • 22
  • 34
-1

Using the itemconfig I solved the problem. Here is the final working code.

import serial
import time    
from tkinter import *
import math
##------------------------------------------##
##------------------------------------------##
ser = serial.Serial('COM5',baudrate = 9600)
ser.flushInput()
##------------------------------------------##
## This function retrieves values from Serial ##
##------------------------------------------##
def con():
    ser_bytes = str(ser.readline().decode('ascii'))
    datasplit = ser_bytes.split(',')
    x = int(datasplit[0])
    y = int(datasplit[1])
    z = int(datasplit[2])
    return x,y,z
##------------------------------------------##
## Creating and Updating arcs for animation ##
##------------------------------------------##
def tilt():
    x,y,z = con()
    c.itemconfig("rect",start = x) # Updates values of arcs start angle.
    c_1.itemconfig("rect",start = y)# "rect" acts as a comman tag
    c_2.itemconfig("rect",start = z)
    root.after(100,tilt)
    print(x,y,z)
##------------------------------------------##
## Main geometry and setting goes here##
##------------------------------------------##
root = Tk()
root.title("Control Panel")
root.geometry('1200x750')
frame_1 = Frame(root)
frame_2 = Frame(root)
frame_3 = Frame(root)
frame_1.grid(row = 0,column = 0)
frame_2.grid(row = 0,column = 1)
frame_3.grid(row = 0,column = 2)
c = Canvas(frame_1,width = 200, height = 200, bg = '#5F9EA0')
c_1 = Canvas(frame_2,width = 200, height = 200, bg = '#5F9EA0')
c_2 = Canvas(frame_3,width = 200, height = 200, bg = '#5F9EA0')
c.pack()
c_1.pack()
c_2.pack()
x = 0
y = 0
z = 0
arc = c.create_arc(1, 1, 200, 200,start = x,extent=-180, fill="red",tags="rect")   
arc_1 = c_1.create_arc(1, 1, 200, 200,start =y,extent=-180, fill="red",tags="rect")
arc_2 = c_2.create_arc(1, 1, 200, 200,start =z,extent=-180, fill="red",tags="rect")
tilt()    
root.mainloop()
cassini
  • 21
  • 1
  • 4
  • Your code still recreate a new arc in every iteration. – acw1668 Feb 28 '20 at 18:15
  • I think for that I will have to include class, which is a bit high-level programming for me. @acw1668 – cassini Feb 29 '20 at 13:50
  • You can create the arc after creating the canvas, then use `c.itemconfig(...)` to change the `start` angle inside `tilt()`. – acw1668 Feb 29 '20 at 14:05
  • @acw1668 did that, now the code looks more compact. I am now reading the serial data in only one place. The tilt function is now used exactly for what it is. – cassini Feb 29 '20 at 18:02
  • As I said, your code recreate a new arc in every iteration. You see only one arc because all the arcs are configured with same `start` option. – acw1668 Mar 01 '20 at 02:35
  • @acw1668 Yes I updated the code, but I haven't posted it here. I took out the arc from function. – cassini Mar 02 '20 at 16:36