Tkinter:在Python 3的框架画布上的矩形按钮。

时间:2018-07-09 18:12:38

标签: python button tkinter tkinter-canvas

我一直在尝试创建一个更像按钮的移动椭圆形。到目前为止,我不打算在单击按钮时执行任何功能,因此我创建了传递功能。

方案如下: 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。

1 个答案:

答案 0 :(得分:0)

画布消失了,因为这是pack的行为-它将导致小部件增大或缩小以适合其子级。该按钮是画布的子级,因此画布会尝试缩小以适合画布。

此解决方案在许多方面都是错误的,例如,要将小部件添加到画布,则不应使用packplacegrid。相反,您应该使用画布方法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能够处理稳定的事件流而不会中断。