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,而是使用packgrid,因为packgrid 都会自动调整窗口大小以适应里面的所有内容。

虽然使用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() 的代码范围是多少?的主要内容,如果未能解决你的问题,请参考以下文章

Unicode 可打印字符的范围是多少?

Excel VBA:自动填充公式的代码,无论左侧列的长度是多少(因此不需要指定范围)

媒体查询的最佳宽度范围是多少

1000行代码出现多少个bug在合理范围内

MCSession 的距离范围是多少?

gl_FragCoord 的范围是多少