mainloop()的代码覆盖范围是什么?

时间:2019-01-27 05:00:59

标签: python tkinter mainloop

我想制作一个python tkinter窗口,在画布上带有自定义移动的小部件以模拟运动。现在,我有一张画布和一个固定的椭圆形小部件。我在基础方面遇到问题; mainloop()。我了解它会在等待用户做某事的过程中运行,但是我很难看到:

  1. 如何控制/确切查看mainloop()在重复什么代码(在哪里,只有tkinter?);

  2. 如何正确中断它并从另一个函数返回它,如果它本身不执行的话;

  3. 应该重复什么代码?所有tkinter对象,还是仅更新变化的对象?改用某种更新操作?最后;

  4. tkinter.mainloop()和window.mainloop()之间的功能区别是什么?也许前面的问题会回答。

我对Swift的使用经验很少,昨天晚上开始学习非常相似的Python。我可能已经尝试了数百种代码突变,目前这些代码正处于测试阶段。我已经将所有内容移入和移出了主循环的可见范围,甚至在整个屏幕上都有数百个微型Python窗口。一切都会做以下两件事之一:什么都不做,或者给我一个错误。由于我什至不知道正在运行什么,或者它是否正在运行,因此我无法诊断任何事情。我的目标只是简单地重复移动一个圆圈一百个像素。我四处寻找资料,但是-可能是我-显然没有资料。我的代码都在这里标记了。该页面最接近我要寻找的页面:Move a ball inside Tkinter Canvas Widget (simple Arkanoid game)。一切似乎都在mainloop下。那么,每一关都重画了一切吗?不幸的是,这是我的全部剧本。我不能只展示作品。由于某种原因,它只会弹出一个小窗口,而不是全屏窗口。 (编辑:我似乎丢失了屏幕尺寸代码)

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”行内循环,这应该调整坐标并移动我的蓝色圆圈。迭代可能不会触及初始值,否则它将重置它们。

1 个答案:

答案 0 :(得分:0)

实际上,调用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的有效示例,包括您在问题中链接的问题。

  

一切似乎都在mainloop下。那么,每次通过都会重绘所有内容吗?

不,不完全是。重绘的唯一对象是需要重绘的事物。在画布上移动对象,调整窗口大小,在窗口上拖动另一个窗口等,所有这些都会在事件队列中放置一个事件,告诉tkinter“此对象需要重绘”。该事件的处理由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()