mainloop() 的代码范围是多少?
Posted
技术标签:
【中文标题】mainloop() 的代码范围是多少?【英文标题】:What range does mainloop() have over code? 【发布时间】:2019-06-20 11:09:54 【问题描述】:我想在画布上制作一个带有自定义移动小部件的 python tkinter 窗口来模拟运动。现在,我有一个画布和一个不动的椭圆形小部件。我在基层遇到问题;主循环()。我知道它在等待用户做某事时运行,但我很难看到:
如何控制/查看 mainloop() 正在重复的代码(在哪里,并且只有 tkinter?);
如果它自己不这样做,如何正确中断它并从另一个函数返回它;
应该重申哪些代码?所有 tkinter 对象,还是仅更新更改的对象?改用某种更新操作?最后;
tkinter.mainloop() 和 window.mainloop() 的功能区别是什么?也许前面的问题会得到解答。
我对 Swift 有一点经验,昨天晚上开始学习非常相似的 Python。我已经对我的代码尝试了可能数百种突变,目前处于测试阶段。我已经将所有内容移入和移出主循环的明显范围,甚至在屏幕上显示了数百个微小的 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 x 650 的窗口,而不是一个很小的窗口。该按钮除了打印什么都不做,这意味着尽管有主循环,但最后的“while”没有运行。它希望它在“while”行内循环,这应该调整坐标并移动我的蓝色圆圈。迭代可能不会触及初始值,否则会重置它们。
【问题讨论】:
好吧,startFunc()
什么都不做 - 它设置的 b
是一个局部变量,与您的全局 b
无关。调用.mainloop()
的小部件并不重要,但在循环中这样做是没有意义的,因为在所有窗口关闭之前它不会返回。做一个正在进行的操作,比如一个动画,方法是做一个步骤的工作,然后打电话.after()
安排下一步的未来某个时间;循环只会阻止 GUI 执行任何操作。
【参考方案1】:
实际上,调用 mainloop 与将其添加到代码中而不是调用 mainloop()
相同:
while the_program_is_running():
event = wait_for_event()
process_the_event(event)
根据经验,mainloop()
应该在 UI 初始化并且您准备好让用户开始与您的程序交互之后调用一次。当它退出时,你通常不会在它之后有任何代码,你的程序就会退出。
如何控制/查看 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 x 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()
。
【讨论】:
如果你的 move_object 函数被运行,那么画布移动,并且函数被重新运行。如果在内部添加了一个条件来决定它是否会继续决定'false',那么这个循环就会终止。 mainloop() 会继续运行还是退出? (我宁愿它仍然可以保持屏幕正常运行!)或者,当这个函数在等待“之后”时,mainloop 还在继续吗? @ScottV.: mainloop 将继续运行直到主窗口被销毁。以上是关于mainloop() 的代码范围是多少?的主要内容,如果未能解决你的问题,请参考以下文章