Tkinter: difficulty getting it to work

I am a newbie at coding and Python. Still, I enjoy every new thing I learn
Am working through my third beginner’s book now. Everything works well when I type in the practice codes and I also get a better understanding why code works as they do.

Until I get to the tkinter chapters…

This is the third time now that I can’t get anything to work, even when I replicate it exactly as it is in the books. I thought trying from a different book might help me see something I missed, but clearly that’s not working.
I looked around a little and by adding tk.mainloop() I finally got things to work in the easiest assignments, but it’s strange to me that the books don’t mention this ‘mainloop’.

Did more people experience this, or am I making some common beginner’s error?

I am a newbie at coding and Python. Still, I enjoy every new thing I
learn
Am working through my third beginner’s book now. Everything works well when I type in the practice codes and I also get a better understanding why code works as they do.

Until I get to the tkinter chapters…

This is the third time now that I can’t get anything to work, even when I replicate it exactly as it is in the books. I thought trying from a different book might help me see something I missed, but clearly that’s not working.
I looked around a little and by adding tk.mainloop() I finally got things to work in the easiest assignments, but it’s strange to me that the books don’t mention this ‘mainloop’.

I suspect they do. Somewhere. It is critical. But maybe they have
omitted it from the examples for simplicity.

Did more people experience this, or am I making some common beginner’s
error?

I expect everyone experiences it at least once when starting to write
GUIs - they almost all work this way.

A GUI is often structured as:

  • set up the widgets
  • run a loop to process their activity (the mainloop)

This is because unlike your typical small procedural programme where you
do some setup, and then do some stuff until it is done, a GUI lays out
some things on the screen and then acts in response to user activity.
Because the user might do anything with the widgets displayed in any
order there’s no predefined sequence of things to do, just user actions
and things to do when those occur.

So after the setup there needs to be a process which listens to the GUI
and acts on iteraction. Because there are many many possible things
which might cause activity (even moving the mouse pointer over a
widget), your setup generally goes:

  • define some widgets
  • specify a few particular things to respond to (eg a button click)

Then the main loop listens to all events, and when the interesting
ones you’d specified occur, calls your handler forthe event. The others
are ignored (well, some have automatic presupplied responses too, like
things with changes colour when they get the focus, etc).

MOst GUI libraries therefore preprovide a “mainloop” function of some
kind whose entire purpose is to sit listening for events and to act on
them. You need to call that to make the GUI function, after all the
setup. Otherwise nothing is listening to events and nothing happens.
Probably your programme reaches the end and quits, instantly.

You may have written the common “prompt for an input and do something”
loop whe learning Python, or other languages. Something like this made
up example:

entries = []
while True:
    answer = input("Enter something, or 'quit' to quit: ")
    if answer == 'quit':
        break
    entries.append(answer)
print("You entered these things:", entries)

That is a mainloop for an interactive terminal: wait for an event
(input()), do something in response. The tkinter mainloop is a more
elaborate one, watching for GUI events instead of keyboard input.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Thank you for your kind help :).

Particularly my latest book is very thorough in writing all the codes down, but it’s not there. Can’t remember reading anything about it either.

Thank you for explaining what it actually does. I just saw it in examples online and decided to add it, being surprised it actually worked. I had no idea why or what it actually did.

Not that I want to hijack this thread in any way, but as I’ve a related question, I thought it better to add to this thread, rather than create a new one - forgive me if I’m wrong in my reasoning.

I’m also learning how to implement a GUI front end with Tkinter and I’ve come across something that confuses me.

This code works fine…

#!/usr/bin/python3

# import tkinter module
from tkinter import *
from tkinter.ttk import *

# creating main tkinter window/toplevel
master = Tk()

# this wil create a label widget
l1 = Label(master, text = "First:")
l2 = Label(master, text = "Second:")

# grid method to arrange labels in respective
# rows and columns as specified
l1.grid(row = 0, column = 0, sticky = W, pady = 2)
l2.grid(row = 1, column = 0, sticky = W, pady = 2)

# entry widgets, used to take entry from user
e1 = Entry(master)
e2 = Entry(master)

# this will arrange entry widgets
e1.grid(row = 0, column = 1, pady = 2)
e2.grid(row = 1, column = 1, pady = 2)

# infinite loop which can be terminated by keyboard
# or mouse interrupt
mainloop()

… but my question is, why (in the above example, taken from a website for which I’ve not noted the URL) does the last line of code not read master.mainloop()

The script works either way, but in what situation would one simply use mainloop() as opposed to, some_name.mainloop() and is it ‘best practice’ to always use some_name.mainloop()

My thanks in advance.

By Rob via Discussions on Python.org at 05Apr2022 16:34:

Not that I want to hijack this thread in any way, but as I’ve a related
question, I thought it better to add to this thread, rather than create
a new one - forgive me if I’m wrong in my reasoning.

I’d have started a new topic named something like “Tkinter: why does
this mainloop call work?” or something like that. But no matter, we’re
here now.

I’m also learning how to implement a GUI front end with Tkinter and I’ve come across something that confuses me.

This code works fine…

#!/usr/bin/python3

# import tkinter module
from tkinter import *
[...]
# creating main tkinter window/toplevel
master = Tk()

[…]

infinite loop which can be terminated by keyboard

or mouse interrupt

mainloop()

... but my question is, why (in the above example, taken from a website for which I've not noted the URL) does the last line of code not read `master.mainloop()`

That would be because the tkinter package provides a convenience
function named mainloop for people not wanting to bother typing
master.mainloop() :slight_smile:

No, really, it does exactly that!

Having a gander at the tkinter source (you’ll have a copy on your
machine too in the Python standard library) we find in
tkinter/__init__.py this code:

def mainloop(n=0):
    """Run the main loop of Tcl."""
    _get_default_root('run the main loop').tk.mainloop(n)

and higher up this code:

def _get_default_root(what=None):
    if not _support_default_root:
        raise RuntimeError("No master specified and tkinter is "
                           "configured to not support default root")
    if _default_root is None:
        if what:
            raise RuntimeError(f"Too early to {what}: no default root window")
        root = Tk()
        assert _default_root is root
    return _default_root

and above that this:

_support_default_root = True
_default_root = None

I expect that when you created master the global
tkinter._default_root became set to that top level widget/app. When you
call mainloop (which got imports by your “from tkinter import *”) it
finds that widget/app, and calls its .mainloop().

The script works either way, but in what situation would one simply use
mainloop() as opposed to, some_name.mainloop() and is it ‘best
practice’ to always use some_name.mainloop()

Personally I would use some_name.mainloop().

I can imagine some handler function somewhere might not have access to
the top level widget. There, it might be sensible to call it this way.
So it is not without value.

It is, in Tk at least, meaningful to run the mainloop in various places

  • all it does is process events and call their handles, which is what
    makes the GUI operate.

Specificly, there’s a method named wait_visibility you can call which
blocks your code until a widget is mapped and rendered. But wait!
Wouldn’t that block the entire GUI? This function has to work by itself
calling the mainloop until that widget is ready, then leaving the loop
and returning to the code which called it, which in turn continues and
resumes the “main” mainloop later.

I’d expect all of Tk’s wait_* methods to operate in this fashion.

The universal widget methods are documented here:
https://tkdocs.com/shipman/universal.html
The wait_visibility method is listed in there.

Cheers,
Cameron Simpson cs@cskk.id.au

My thanks to you for the quick and detailed response, as well as the info link, which I will visit and study.

Different Forums have different ways of operating, but now that I’m aware of how things are done around here, I’ll adjust my SOP; thanks for the advice.

Peace.