stop tkinter window from freezing while program is sleeping

Calling time.sleep() will stop your program doing anything until it finishes sleeping. You need Tkinter to keep processing events until it should run the next part of your code.

To do that, put the next part of your code in a separate function, and get Tkinter to call it when it's ready. Typically, you want this to happen when the user triggers it (e.g. by clicking a button), so you need to bind it to an event (docs). If you actually want it to happen after a fixed time, you can use the .after() method on any tkinter widget (docs).

GUI programming takes a bit of getting used to. You don't code as a series of things happening one after the other, you write separate bits of code which are triggered by what the user does.

Terminology note: if your Python files import each other, you have three modules, but it's still all one program. Talking about the "first program" will confuse people.


H.E.P - The traditional way to do this does indeed involve using a separate thread and co-ordinating the work between the "worker" thread and the GUI thread using some sort of polling or eventing mechanism.

But, as Thomas K. points out, that can get very complex and tricky, especially regarding Python's use of the Global Interpreter Lock (GIL) etc. and having to also contend with Tkinter's processing loop.

(The only good reason to use a multi-threaded GUI is if you absolutely MUST ensure that the GUI remains responsive during a potentially long-running background task, which I don't believe is the issue in this case.)

What I would suggest instead is a generator-based "co-routine"-type architecture. As noted in "The Python (2.7) Language Reference", Section 6.8, [the "yield" statement is used when defining a generator function and is only used in the body of the generator function. Using a yield statement in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.]

(This effectively forms the basis of a co-routine architecture. (ed.))

[When a generator function is called, it returns an iterator known as a generator iterator, or more commonly, a generator. The body of the generator function is executed by calling the generator’s next() method repeatedly until it raises an exception.

When a yield statement is executed, the state of the generator is frozen and the value of expression_list is returned to next()‘s caller. By “frozen” we mean that all local state is retained, including the current bindings of local variables, the instruction pointer, and the internal evaluation stack: enough information is saved so that the next time next() is invoked, the function can proceed exactly as if the yield statement were just another external call.] (Also see "PEP 0342 - Coroutines via Enhanced Generators " for additional background and general info.)

This should allow your GUI to call the next part of your algorithm specification generator, on demand, without it having to be put to sleep until the operator presses the "Next" button. You would basically just be creating a little 'domain-specific language', (DSL), consisting of just the list of steps for your presentation of this particular algorithm, and the generator (iterator) would simply execute each next step when called (on demand).

Much simpler and easier to maintain.