我想在画布上创建一个带有自定义移动小部件的python tkinter窗口来模拟运动。现在,我有一个画布,一个不动的椭圆形小部件。我在基层有问题;主循环()。我知道它会等待用户做某事,但我很难看到:
我对Swift有一点经验,昨天晚上开始学习非常相似的Python。我已经尝试了数百个突变到我的代码,目前正处于测试阶段。我已将所有内容移入和移出mainloop的明显范围,甚至在屏幕上都有几百个小的Python窗口。一切都做两件事之一:它什么都不做,或者给我一个错误。由于我不知道什么是运行,或者它正在运行,我无法诊断任何东西。我的目标只是重复移动一百个像素的圆圈。我已经四处寻找消息来源,但是 - 它可能是我 - 一个明显的稀缺。我的代码在这里都标记了。此页面最接近我要找的内容:Move a ball inside Tkinter Canvas Widget (simple Arkanoid game)。一切似乎都在主循环之下。那么,每一次都重绘一切?不幸的是,这是我的整个剧本;我不仅可以展示作品。它出于某种原因,只会打开一个小窗口,而不是一个全屏窗口。 (编辑:我似乎丢失了屏幕尺寸代码)
import tkinter
import time
# Initial values for circle's corners and start idicator ('b'):
x1 = 10
y1 = 10
x2 = 210
y2 = 210
b = 0
# Window ('window')
window = tkinter.Tk()
# Canvas ('area')
area = tkinter.Canvas(window, width=1368, height=650)
area.place(x=0, y=0)
# Ovals to be placed on 'area'
oval1 = area.create_oval(x1,y1,x2,y2,fill='#42befe')
oval2 = area.create_oval(100,10,300,210,fill='#d00000')
# Turns b to 1 to start shifting when 'butt' is pressed:
def startFunc():
b = 1
print('b = 1')
# My button to activate 'startFunc'
butt = tkinter.Button(window, text='Start movement', command=startFunc)
butt.pack()
# Adjusts the x and y coordinates when they are fed in:
def Shift(A, B, C, D):
print('Shift activated.')
window.after(1000)
print('Edit and return:')
A += 100
B += 100
C += 100
D += 100
return(A, B, C, D)
# Problems start about here: my Mainloop section;
# I have little idea how this is supposed to be.
while True:
if b == 1:
# Takes adjusted tuple
n = Shift(x1, y1, x2, y2)
print('Returned edited tuple.')
# Changes coordinates
x1 = n[0]
y1 = n[1]
x2 = n[2]
y2 = n[3]
print(f'{x1}, {y1}, {x2}, and {y2}')
# Reiterate moving oval
oval1 = area.create_oval(x1,y1,x2,y2,fill='#42befe')
#Does this re-run 'window' relations outside here, or only within the 'while'?
window.mainloop()
它应该显示一个1368乘650的窗口,而不是一个小窗口。该按钮除了打印之外什么都不做,这意味着尽管有主循环,最后的'while'仍未运行。它希望它在'while'行内循环,这应该调整坐标并移动我的蓝色圆圈。迭代可能不会触及初始值,否则会重置它们。
实际上,调用mainloop与将其添加到代码中而不是调用mainloop()
相同:
while the_program_is_running():
event = wait_for_event()
process_the_event(event)
根据经验,在UI初始化之后,mainloop()
应该被调用一次,并且您已准备好让用户开始与您的程序进行交互。当它退出时,你通常不会有任何代码,你的程序将退出。
如何控制/查看mainloop()重复的代码(在哪里,只有tkinter?);
我不知道“重申”是什么意思。它不会运行任何代码,除了它自己的内部代码。它只是等待事件,然后将它们分派给处理程序。
如果没有自己中断,如何正确地中断它并从另一个函数返回它;
在正在运行的程序中执行此操作非常罕见。通常,调用mainloop
是您的程序在用户开始与之交互之前执行的最后一件事,并且一旦退出程序就退出。
但是,要回答如何中断它的具体答案,可以调用根窗口的quit
方法。这将导致最近对mainloop()
的回复。
应该重申什么代码?所有tkinter对象,还是仅更新更改的对象?改为使用某种更新操作?
这个问题很难回答,因为它没有多大意义。当你调用mainloop()
时,它会监视所有tkinter对象上的所有事件。
tkinter.mainloop()和window.mainloop()之间的功能有什么区别
它们具有完全相同的效果和行为。 Tkinter奇怪地选择从任何小部件中提供mainloop
。调用它的最常用方法是来自tkinter模块本身,或来自根窗口。
我的目标只是重复移动一百个像素的圆圈。
通常的做法是创建一个将其移动一百个像素的函数。然后,该函数(或调用它的函数)可以将自己置于将来运行的事件队列中。
例如,以下代码将每秒移动一个画布对象100像素,直到程序退出:
def move_object():
the_canvas.move(item_id, 100, 0)
the_canvas.after(1000, move_object)
调用它时,它会将项目向右移动100个像素。然后,它将在事件队列上对其自身进行新的调用,以便在大约1000毫秒内拾取和处理。
在本网站上有许多使用after
的工作示例,包括您在问题中链接的问题。
一切似乎都在主循环之下。那么,每一次都重绘一切?
不,不完全是。重绘的唯一对象是需要重绘的对象。在画布上移动对象,调整窗口大小,在窗口上拖动另一个窗口等,都会在事件队列上放置一个事件,告诉tkinter“此对象需要重绘”。该事件的处理由mainloop
自动发生。如果您的应用程序中没有发生任何事情,那么mainloop就不会重新绘制任何内容。
它应该显示一个1368乘650的窗口,而不是一个小窗口
那是因为你没有给主窗口一个大小。你已经给了画布一个大小,但是你使用的是place
,这不会导致包含窗口增长或缩小以适应。作为初学者,你应该完全避免使用place
而是使用pack
或grid
,因为pack
和grid
都会自动调整窗口大小以适应内部的所有内容。
虽然使用place
的感觉很简单,但实际上它通常要求你比使用其他几何管理器做更多的工作,并且它导致GUI对变化没有特别的响应。
while True:
你几乎不应该在tkinter中这样做。 Tkinter - 以及几乎所有基于事件的程序 - 都依赖于稳定的事件流。当您有一个无限循环时,它无法处理这些事件。您可以显式调用以更新循环内的屏幕,但这样做效率低,应该避免。如果你需要定期做一些事情,创建一个封装循环体的函数,然后使用after
让mainloop
在处理事件时运行它。
window.after(1000)
如果没有第二个参数,你几乎不应该以这种方式使用after
。这种用法在功能上与调用time.sleep(1)
没有区别,因为它阻止了mainloop
处理事件。您应该构造代码以允许mainloop
处理稳定的事件流。
while True: ... window.mainloop()
你肯定需要避免在循环中调用mainloop
。一个表现良好的tkinter程序应该只调用一次mainloop()
。