我一直在尝试创建一个更像按钮的移动椭圆形。到目前为止,我不打算在单击按钮时执行任何功能,因此我创建了传递功能。
方案如下: tkinter窗口中的框架在指定位置被洋红色画布覆盖,并带有圆圈(黄色)。这个圆圈实际上是一个按钮,按下该按钮会打开一个弹出菜单,其中显示一些信息(现在不是必需的)。我设法创建了圆圈,但是努力将按钮加入椭圆形。按钮和圆圈必须在一起,因为这对应该每3秒在画布框架中移动一次(声音像GPS点,但点是按钮)。
但是当我尝试创建按钮时,画布消失了,并且框架根据按钮的宽度调整了大小。 请帮助我识别错误和相应的正确代码:
enter code here
from tkinter import *
import random
import time
def nothing():
pass
main = Tk()
frame_1 = Frame(main)
frame_1.grid(row=0, column=0)
main_canvas = Canvas(frame_1, width=200, height=200, bg='magenta')
oval = main_canvas.create_oval(20, 20, 40, 40, outline='black', fill='yellow')
main_canvas.pack()
frame_2 = Frame(main)
frame_2.grid(row=0, column=1)
'''
button2 = Button(main_canvas, text="Q", command=nothing, anchor=W)
button2.configure(width=3, activebackground="#33B5E5", relief=FLAT)
button2_window = main_canvas.create_window(10, 10, anchor=NW, window=button2)
button2.pack(side=TOP)
'''
label_f2_1 = Label(frame_2, text="")
label_f2_1.pack()
label_f2_2 = Label(frame_2, text="")
label_f2_2.pack()
x_current, y_current = 30, 30
for loops in range(86400):
x_new = random.randint(10, 190)
y_new = random.randint(10, 190)
main_canvas.move(oval, x_new-x_current, y_new-y_current)
x_current, y_current = x_new, y_new
main_canvas.update()
time.sleep(1)
now = str(time.ctime())
label_f2_2.configure(text=now[10:])
label_f2_1.configure(text=now[0:10])
# print(time.localtime())
main.mainloop()
使用在python 3.7解释器上运行的PyEdu。
答案 0 :(得分:0)
画布消失了,因为这是pack
的行为-它将导致小部件增大或缩小以适合其子级。该按钮是画布的子级,因此画布会尝试缩小以适合画布。
此解决方案在许多方面都是错误的,例如,要将小部件添加到画布,则不应使用pack
,place
或grid
。相反,您应该使用画布方法create_window
。
但是,您完全不需要椭圆形内部的按钮。您可以创建一个绑定,只要用户直接在椭圆上单击,就将调用一个函数。
例如,以下操作将导致在单击椭圆形时调用函数showInfo
:
def showInfo(event):
print("you clicked on the oval")
main_canvas.tag_bind(oval, "<1>", showInfo)
但是,由于您执行动画循环的方式,因此效果不佳。您的代码比其他任何事情都睡得更多,这使得tkinter很难处理事件。 sleep
处于休眠状态时,Tkinter无法处理事件。
代替编写for
循环,您需要编写一个函数来执行循环内正在执行的所有操作(即:它绘制一帧动画)。将来,该函数可以使用after
再次调用自身,建立永久循环。
例如:
def doOneIteration():
newx = random.randint(10, 190)
newy = random.randint(10, 190)
main_canvas.coords(oval, newx, newy, newx+20, newy+20)
now = str(time.ctime())
label_f2_2.configure(text=now[10:])
label_f2_1.configure(text=now[0:10])
main.after(1000, doOneIteration)
doOneIteration()
第一次调用doOneIteration
时,它将执行循环体内的所有操作。然后,完成后将导致自己在一秒钟内再次被调用。下次调用它时,它将完成工作,然后再次使其自身在一秒钟内被调用。只要程序运行,它就会一直执行。
这里的优点是,您绝不会让程序进入睡眠状态。这样可以确保tkinter能够处理稳定的事件流而不会中断。