与Tkinter应用程序一起运行循环 [英] Running a loop alongside a Tkinter application

查看:404
本文介绍了与Tkinter应用程序一起运行循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名高中编程专业的学生,​​我有一个小问题.我的任务是在Tkinter编写一个简单的游戏,其中冰柱从天花板上掉下来,您必须避免使用鼠标.很简单.但是,我遇到了一个问题.每当我在Tkinter应用程序中运行循环时,它都不会打开.我已经尝试过使用time.sleep()每0.5秒暂停一次的for循环,并在循环结束后立即打开窗口.为了使循环在Tkinter中工作,我需要做些特殊的事情吗?

I am a high school programming student and I have a small question. I have been tasked with writing a simple game in Tkinter where an icicle falls from the ceiling and you have to avoid it with your mouse. Simple enough. However, I have hit an issue. Whenever I run a loop in a Tkinter application, it won't open. I've tried with a for loop that pauses every .5 seconds using time.sleep() and the window opens as soon as the loop finishes. Is there some special thing I need to do to make loops work in Tkinter?

from Tkinter import *
import time
import random

class App:
    def __init__(self, parent):
        self.frame = Frame(root, bg= '#1987DF', width=800, height=800)
        self.frame.bind("<Motion>", self.motionevent)
        self.frame.pack()
        #self.run()
    def randhex(self):
        b = "#"
        for i in range(1, 7):
            a = random.randint(0, 15)
            if a == 10:
                a = "A"
            elif a == 11:
                a = "B"
            elif a == 12:
                a = "C"
            elif a == 13:
                a = "D"
            elif a == 14:
                a = "E"
            elif a == 15:
                a = "F"
            b = b+str(a)
        return b

    def motionevent(self, event):
        xpos, ypos, bg = event.x, event.y, self.randhex()
        str1 = "X : %d  Y : %d BG : %s" % (xpos, ypos, bg)
        root.title(str1)
        x,y, delta = 100, 100, 10
        self.frame.config(bg=bg)

    def run(self):
        for i in range(0, 10):
            time.sleep(.5)
            print 'i'
            self.frame.config(bg=self.randhex())

root = Tk()
app = App(root)
root.mainloop()

当前要做的只是在鼠标移动时更改背景.当 init 中表示self.run()的行取消注释时,它将打印'i'10次,然后窗口将打开.帮助吗?

Currently all it is supposed to do is change the background when the mouse moves. When the line in init that says self.run() is uncommented it will print 'i' 10 times then the window will open. Help?

推荐答案

编写基于事件的程序与编写传统程序不同.已经有一个无限循环在运行,并且像任何无限循环一样,如果在内部放置另一个循环,则直到内部循环结束,外部循环才能继续.由于外循环是导致屏幕刷新并处理事件的原因,因此内循环有效地冻结了您的应用程序,直到它们完成为止.

Writing an event based program is not the same as writing traditional programs. There is already an infinite loop running, and like any infinite loop, if you place another loop inside, the outer loop can't continue until the inner loop finishes. Since the outer loop is what causes the screen to refresh and events to be processed, inner loops effectively freeze your app until they are done.

由于已经有一个循环在运行,因此您无需创建另一个循环.您需要做的就是一次将少量作业添加到事件队列中.实际上,每个作业都是您的内部循环的一次迭代.

Since there is already a loop running you don't need to create another loop. All you need to do is add little jobs to the event queue one at a time. Each job is, in effect, one iteration of your inner loop.

例如,如果您要编写这样的内部循环:

For example, if you wanted to write an inner loop like this:

for i in range(10):
    print "i:", i

...而是将事件添加到事件队列中,并且每次事件循环迭代时(或更准确地说,每次完成处理任何其他事件的时间),都会对循环进行一次迭代.您是这样做的:

... you would instead add an event to the event queue and each time the event loop iterates (or more precisely, each time it finishes processing any other events) it will do one iteration of your loop. You do it like this:

def do_one_iteration(i):
    print "i:", i
    if i < 9:
        root.after_idle(do_one_iteration, i+1)

然后,在您第一次调用do_one_iteration之后,它将把自身的下一个迭代放置在事件队列中,并继续这样做直到它决定完成为止.

Then, after the first time you call do_one_iteration, it will place the next iteration of itself on the event queue, and continue to do so until it decides it is done.

通常,当用户按下一个按钮(例如:开始"按钮)时,您会呼叫do_one_iteration.调用一次,然后做一点工作(即:将冰柱向下移动几个像素),然后重新安排自己的时间.

Typically you would call do_one_iteration when the user presses a button (eg: the "start" button). Call it once, then it does one bit of work (ie: moving the icicle down a couple of pixels) and then reschedules itself.

在游戏开发中,您可能有一个名为update_display的函数,负责重绘所有内容.例如,它可以从每个冰柱的Y坐标中减去1.您可以为左右箭头添加绑定以移动播放器(通过增加或减小X坐标),并且更新功能将使用这些新坐标来重绘播放器.

In game development you might have a function called update_display which is in charge of redrawing everything. It could, for example, subtract 1 from the Y coordinate of each icicle. You can add bindings for the left and right arrows to move the player (by incrementing or decrementing the X coordinate), and your update function would use these new coordinates to redraw the player.

顺便说一句,您可以通过使用after而不是after_idle稍微延迟后调用该函数来减慢程序速度.此延迟可用于控制帧速率.例如,假设更新几乎是瞬时的(可能是您的情况),则以参数41(毫秒)调用after会产生大约24 fps的帧速率(24帧乘以41毫秒等于984毫秒,或者大约每秒24帧)

By the way, you can slow down your program by using after instead of after_idle to call the function after a slight delay. This delay can be used to control the frame rate. For example, assuming the update is nearly instantaneous (and it probably will be in your case), calling after with an argument of 41 (milliseconds) yields a framerate of approximately 24 fps (24 frames times 41 milliseconds equals 984 milliseconds, or roughly 24 frames per second)

这听起来可能很复杂,但是一旦执行一次或两次,实际上就非常容易.

It may sound complicated but it's really pretty easy in practice once you do it once or twice.

这篇关于与Tkinter应用程序一起运行循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆