我正在尝试使用tkinter可视化python中的正弦波加法,并且试图在每个圆心之间构建线,但是到目前为止,我尝试过的工作并没有达到我的预期。是否可以解决我尝试过的问题(请参见代码),或者仅使一条线的一个坐标点独立于另一条坐标线移动?
如您在代码中看到的那样,如果您运行它,我就尝试了一种方法,其中每次迭代都删除前一行,并创建一个新的方法。当我运行代码时,实际上就像我想要的那样,在圆的每个中心之间都有一条线,但事实是这些线持续存在并且不会擦除自身。由于某些原因,canvas.delete(line)似乎没有按我预期的那样工作。
这是完整的代码。有趣的部分是在“ updateline”功能中,在“ act()”函数中。
import math
import tkinter as tk
##important to know! -- the way I'm creating the circles is by setting an object, the bounds of the circle, depending on amplitude asked by user.
##then the programs calculates the path of these bounds, depending on circles, amplitude, phase and frequency of the sine waves asked by the user from the tkinter GUI.
##finally, the program creates and moves along this path a circle, representing visually the sine wave.
top = tk.Tk()
top.title('Superposition')
choice = tk.Tk()
choice.title('Parametres')
f = tk.Frame(choice,bd=3)
f.pack(side='top')
g = tk.Frame(choice,bd=3)
g.pack(side='bottom')
tk.Label(f,text="nbre ondes:",width = 10).grid(row=0,column=0)
sines = tk.Spinbox(f,from_=1,to=50,width=10,textvariable=tk.DoubleVar(value=2))
sines.grid(row=0,column=1)
sines.delete(0,5)
sines.insert(0,2)
delai = tk.Scale(g, orient='vertical', from_=100, to=1,resolution=1, length=100,label='delai')
delai.grid(row=0,column=0)
hauteur = tk.Scale(g, orient='vertical', from_=1100, to=100,resolution=100, length=100,label='fenetre')
hauteur.grid(row=0,column=1)
taillec1 = tk.Scale(g, orient='vertical', from_=3.5, to=0.1,resolution=0.1, length=100,label='taille')
taillec1.grid(row=0,column=2)
delai.set(20)
hauteur.set(600)
taillec1.set(1.5)
def grilledechoix():
numberofsines = int(sines.get())
for i in f.grid_slaves():
if int(i.grid_info()["row"]) > numberofsines+2:
i.grid_forget()
for i in range(1,numberofsines+1):
tk.Label(f,text="phase n."+str(i),width = 10).grid(row=i+2,column=4)
phase = tk.Spinbox(f,from_=-180,to=180,width=10)
phase.grid(row=i+2,column=5)
phase.delete(0,5)
phase.insert(0, 0)
for i in range(1,numberofsines+1):
tk.Label(f,text="amp. n."+str(i),width = 10).grid(row=i+2,column=0)
ampli = tk.Spinbox(f,from_=1,to=10000000,width=10)
ampli.grid(row=i+2,column=1)
ampli.delete(0,5)
ampli.insert(0,10)
for i in range(1,numberofsines+1):
tk.Label(f,text="freq n."+str(i),width = 10).grid(row=i+2,column=2)
freq = tk.Spinbox(f,from_=-1000,to=1000,width=10)
freq.grid(row=i+2,column=3)
freq.delete(0,5)
freq.insert(0,5)
def act():
h = g.grid_slaves()[1].get()
delai = g.grid_slaves()[2].get()
taillec1 = g.grid_slaves()[0].get()
w = h
ampdict = {'box1':100 * ((h/700)*taillec1)}
frqdict = {}
aaadict = {}
fffdict = {}
phadict = {}
numberofsines = int(sines.get())
sin = lambda degs: math.sin(math.radians(degs))
cos = lambda degs: math.cos(math.radians(degs))
for i in range(1,numberofsines+1):
fffdict['box'+str(numberofsines-i+1)] = f.grid_slaves()[(2*i)-2].get()
aaadict['box'+str(numberofsines-i+1)] = f.grid_slaves()[(2*i)-2+2*numberofsines].get()
phadict['box'+str(numberofsines-i+1)] = f.grid_slaves()[(2*i)-2+4*numberofsines].get()
for i in range(1,numberofsines+1):
ampdict['box'+str(i)] = (float(ampdict['box1'])/float(aaadict['box1'])) * float(aaadict['box'+str(i)])
frqdict['box'+str(i)] = float(fffdict['box'+str(i)])/float(fffdict['box1'])
class obj(object):
cos0, cos180 = cos(0), cos(180)
sin90, sin270 = sin(90), sin(270)
def __init__(i, x, y, rayon):
i.x, i.y = x, y
i.rayon = rayon
def bounds(i):
return (i.x + i.rayon*i.cos0, i.y + i.rayon*i.sin270,
i.x + i.rayon*i.cos180, i.y + i.rayon*i.sin90)
def updateposition(canvas, id, cent, obj, path):
obj.x, obj.y = next(path)
x0, y0, x1, y1 = canvas.coords(id)
oldx, oldy = (x0+x1) // 2, (y0+y1) // 2
dx, dy = obj.x - oldx, obj.y - oldy
canvas.move(id, dx, dy)
canvas.move(cent, dx, dy)
canvas.after(delai, updateposition, canvas, id, cent, obj, path)
def updateline(canvas, line, robj0, cent0, robj1, cent1):
x00, y00, x01, y01 = canvas.coords(cent0) ##defining coords of the two ovals asked, representing centers of circles
x10, y10, x11, y11 = canvas.coords(cent1)
oldx0, oldy0 = (x00+x01) // 2, (y00+y01) // 2 ##defining center coords of the two ovals
oldx1, oldy1 = (x10+x11) // 2, (y10+y11) // 2
dx0, dy0 = robj0.x - oldx0, robj0.y - oldy0 ##defining the deltax and deltay, difference of movements between frames, of the two ovals
dx1, dy1 = robj1.x - oldx1, robj1.y - oldy1
canvas.after(delai, canvas.delete, line) ##deleting previous line, does not work and I don't know why. I've also tried 'canvas.delete(line)', giving same results
canvas.create_line(oldx0+dx0, oldy0+dy0, oldx1+dx1, oldy1+dy1) ##creating new line
canvas.after(delai, updateline, canvas, line, robj0, cent0, robj1, cent1) ##function invoking itself after delay 'delai'
def posobj(pt,ang,deltang):
while True:
yield pt.x + pt.rayon*cos(ang), pt.y + pt.rayon*sin(ang)
ang = (ang+deltang)%360
try:
top.pack_slaves()[0].destroy()
except:
pass
canvas = tk.Canvas(top, bg='white', height=h, width=w)
canvas.pack(side='right')
robj = {}
r = {}
posobjet = {}
line = {}
cent = {}
## the following 'for' loop creates a number of circles corresponding to sine waves, as much as the user asked.
for i in range(1,int(sines.get())+2):
if i != int(sines.get())+1:
if i == 1:
robj[str(i)] = obj(h/2,h/2,float(ampdict['box'+str(i)]))
r[str(i)] = canvas.create_oval(robj[str(i)].bounds(),fill='',outline='black')
cent[str(i)] = canvas.create_oval(h/2+h/200,h/2+h/200.,h/2-h/200,h/2-h/200, fill='white', outline='red')
posobjet[str(i)] = posobj(robj[str(i)],float(phadict['box'+str(i)]),float(frqdict['box'+str(i)]))
else:
robj[str(i)] = obj(robj[str(i-1)].x,robj[str(i-1)].y,float(ampdict['box'+str(i)]))
r[str(i)] = canvas.create_oval(robj[str(i)].bounds(),fill='',outline='black')
cent[str(i)] = canvas.create_oval(robj[str(i)].x+h/200,robj[str(i)].y+h/200,robj[str(i)].x-h/200,robj[str(i)].y-h/200, fill='white', outline='blue')
line[str(i)] = canvas.create_line(0,0,0,0)
posobjet[str(i)] = posobj(robj[str(i)],float(phadict['box'+str(i)]),float(frqdict['box'+str(i)]))
top.after(delai, updateposition, canvas, r[str(i)], cent[str(i)], robj[str(i)], posobjet[str(i-1)])
##here I'm invoking the updateline function using the constant 'delai', the line i, and objects defining the bounds of the center objects, the little blue/red dots appearing as the center of each circles(run the code, it'll be easier to understand)
top.after(delai, updateline, canvas, line[str(i)], robj[str(i-1)], cent[str(i-1)], robj[str(i)], cent[str(i)])
else:
robj[str(i)] = obj(robj[str(i-1)].x,robj[str(i-1)].y,h/200)
r[str(i)] = canvas.create_oval(robj[str(i)].bounds(),fill='white',outline='red')
cent[str(i)] = canvas.create_oval(robj[str(i)].x+h/200,robj[str(i)].y+h/200,robj[str(i)].x-h/200,robj[str(i)].y-h/200, fill='white', outline='red')
line[str(i)] = canvas.create_line(0,0,0,0)
top.after(delai, updateposition, canvas, r[str(i)], cent[str(i)], robj[str(i)], posobjet[str(i-1)])
##2nd and last time invoking the updateline function, for the line between the last circle's point and the final red point.
top.after(delai, updateline, canvas, line[str(i)], robj[str(i-1)], cent[str(i-1)], robj[str(i)], cent[str(i)])
top.mainloop()
ok = tk.Button(f,text='NBRE',command=grilledechoix)
ok.grid(row=0,column=2)
ac = tk.Button(f,text='APPLY',command=act)
ac.grid(row=0,column=3)
grilledechoix()
act()
我希望一旦updateline函数再次调用自身,这些行就会消失,因为更新行中有'canvas.delete(line)'行,我真不明白为什么这样做。 无论如何,如果您有解决方案来使行移动,而不必在每次调用函数时都创建和删除它们,请随时告诉我。
谢谢!
答案 0 :(得分:0)
如果我正确理解了问题,则认为问题出在以下代码上:
canvas.after(delai, canvas.delete, line)
canvas.create_line(oldx0+dx0, oldy0+dy0, oldx1+dx1, oldy1+dy1)
canvas.after(delai, updateline, canvas, line, robj0, cent0, robj1, cent1)
它无法将 new 行重新分配给下一次调用的line
变量。而是尝试:
canvas.after(delai, canvas.delete, line)
line = canvas.create_line(oldx0+dx0, oldy0+dy0, oldx1+dx1, oldy1+dy1)
canvas.after(delai, updateline, canvas, line, robj0, cent0, robj1, cent1)
我运行它时除去了多余的行。让我知道是否错过了重点。