I am learning about Tkinter and was wondering if it would cause errors if I did the following:
import tkinter as tk #import modules
from tkinter import ttk
parent=tk.Tk() #create first instance
card1="k spades"
card2="k diamonds"
comboform=ttk.Combobox(parent,textvariable='form',values=[card1,card2,"both","neither"])#create combobox input form
comboform.grid(row=0,column=0)#added to grid
parent.geometry("200x200")
parent.mainloop()#displays tkinter window
#window exited
parent=tk.Tk()#new instance created
label=tk.Label(parent,text="hi")#label produced
label.pack()#added to window
parent.mainloop()
If I click the exit cross is that the same as parent.destroy(); is that good practice? I know you're only supposed to run mainloop() once and have one Tk() instance but if it's destroyed is it going to cause problems? It's not like I'm creating a class the produces a Tk() instance, where there's a risk of multiple instances existing at once.
I am hoping to, eventually, have an application running in the IDLE and then have a tkinter window appear, presenting an input widget of some kind. After the user gives their input, the window would close and the user would continue in the main window. But could I then do it again, opening new windows (like the above code) on the provision that the instance of Tk() is destroyed each time?
If you've destroyed the root window and then create a new one, that's perfectly fine.
The problem with creating multiple instances of Tk is that most people don't understand what that actually does. Having multiple instances of Tk is fine as long as you realize that they operate in completely memory spaces and widgets and bindings in one can't interact with widgets and bindings in the other.
All of that being said, the best practice is to create a single root window at the start of the program, and it stays alive until the program exits. If you need additional windows, the best practice is to create instances of Toplevel.
I know that I can subclass a tk.Frame (or ttk.Frame) and add that to a TopLevel to make secondary windows, but I'm not sure how I should use that as the main window. I know that creating an instance of a Frame class and calling .mainloop() on it seems to work for using it as the main window, but I feel like that's bad practice...
What do other people do when they are making GUI layouts that they want to have available to main windows and secondary windows?
Create a subclass of a Frame, and then put it either in the root window or a toplevel. In either case, you still call mainloop only once on the root window.
The only care you have to take is that you have to be careful about letting the user close the root window, because it will cause all of the other windows to be destroyed.
If you're creating a program that can have multiple windows, you might want to consider hiding the root window and always putting your window in a Toplevel. Of course, when you do that you need to make sure you destroy the root window whenever the last toplevel window is destroyed, or your program will continue to run but the user will have no way to access it.
Do you mean having a home screen that you can flip back to? If so, you can try looking here: Using buttons in Tkinter to navigate to different pages of the application?
I am trying to create a basic Tkinter window.
According to on-line tutorials, to create a window one must use the following:
import Tkinter
window=Tkinter.Tk()
window.mainloop()
But when I try the same code python directly displays the window in window=Tkinter.Tk() and window.mainloop() has no effect.
Can anyone explain why ?
EDIT: The code works perfectly when I put it in a file and run it. It just doesn't work from interactive prompt.
The call to mainloop is there so that you can interact with the Window once it's created. If you had a Python script that only did this:
import Tkinter
window = Tkinter.Tk()
The script would exit immediately after window was created, so you'd be luckily to even see it get drawn before it disappeared as the script exited. (That is if window was even drawn at all; in my tests on both Linux and Windows, window was never drawn unless mainloop was called; even if I put a call to time.sleep after the Tkinter.Tk() call, window would only be drawn without a mainloop call in the interactive prompt).
The mainloop() also (and most importantly) allows Tkinter to listen for events to occur on the Tk object, such as pressing buttons, radios, etc. that might be embedded in it, and dispatch those events to methods you have bound to the event being triggered. Without that functionality you'd just have a window that you can look at and not much else.
I am trying to build an application with a main window, and a background thread that checks a certain condition in a loop, and when the condition is met, brings the main window to the front.
To bring the window to the front i use the lift() method, but it doesn't work.
So I did the following experiment from the python command line:
from Tkinter import *
root = Tk()
A tk window appears. Minimize the window and then:
root.lift()
Nothing happens. I also tried start the window's mainloop before lifting:
import thread
# start mainloop in separate thread so we can continue typing
thread.start_new_thread(root.mainloop, ())
root.lift()
Again, nothing happens. In my actual code it is even worse - once I call lift(), the window is stuck and stops responding.
What am I doing wrong?
(I'm using Python 2.7.2 on Windows 7.)
You cannot run the mainloop in a thread different from the one where you create the widgets. In fact, you can't interact with widgets at all from another thread.
To revert the effects of minimizing the window you need to use the deiconify method.
Every tkinter tutorial I have seen claims that tkinter.mainloop must be called for windows to be drawn and events to be processed, and they always call this function, even in hello world programs. However, when I try these out in the interactive shell, windows are drawn correctly without having to call mainloop. This example of embedding matplotlib graphics in tkinter produces a relatively complex application, with buttons for panning, zooming and resizing a plot within a tkinter window, and again, this all works if you remove the call to mainloop and run the code in the interactive shell. Of course, if I run the script (with mainloop removed) outside the interactive shell, the program ends too quickly to see what happens, but if I add a call to input to hold the program open everything works correctly (I'm running python 3.2.2 on linux).
So what exactly does mainloop do, and when is it necessary to call it?
EDIT:
To clarify, if I open up the GNOME terminal and type
$python3
>>> import tkinter
>>> root = tkinter.Tk()
a window immediately appears without having to call mainloop, and more complex tkinter functionality seems to work as well (for example, adding buttons to the window). In IDLE, a call to mainloop is necessary. It was my understanding that nothing should be drawn, and no events should be processed, until mainloop is called.
The answer to your main question is, you must call mainloop once and only once, when you are ready for your application to run.
mainloop is not much more than an infinite loop that looks roughly like this (those aren't the actual names of the methods, the names merely serve to illustrate the point):
while True:
event=wait_for_event()
event.process()
if main_window_has_been_destroyed():
break
In this context, "event" means both the user interactions (mouse clicks, key presses, etc) and requests from the toolkit or the OS/window manager to draw or redraw a widget. If that loop isn't running, the events don't get processed. If the events don't get processed, nothing will appear on the screen and your program will likely exit unless you have your own infinite loop running.
So, why don't you need to call this interactively? That's just a convenience, because otherwise it would be impossible to enter any commands once you call mainloop since mainloop runs until the main window is destroyed.
Compare a program with an interactive GUI to a program that calculates the hundredth Fibonacci number. All the latter program has to go through a series of steps in order, top to bottom. The set of steps and their sequencing can be known in advance, and it'll remain constant no matter how many times you run the program.
But the GUI program is different: at any given moment, it has to be able to handle all sorts of different kinds of events and interactions. This requirement is often implemented using a programming construct called an event loop. An event loop is the central control structure of a program. It waits for an event to happen, and then dispatches the appropriate handler.
You didn't mention which interactive shell you're using, but I'm guessing it's IDLE. IDLE itself is a Tkinter program, and it already has an event loop going. So possibly the Tkinter code you are typing into the shell is getting bound to IDLE's event loop.
When you execute your code, the tkinter window will refuse to open without there being a mainloop function.
For example this will not work:
from tkinter import*
root=Tk()
This, however, will work:
from tkinter import*
root=Tk()
root.mainloop()
If you’re using python interective shell, you don’t need to call the root.mainloop() function. But if you are coding in a file, suppose one in IDLE, you need to call out the mainloop() function in order for your program to work as follows:
from tkinter import *
root = Tk()
# Elements in the GUI must go here eg:
lbl = Label(root, text=“Text”)
lbl.pack()
# At the end of the program, do this:
root.mainloop()
As follows:
from tkinter import *
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.pack()
canvas.create_line(0, 0, 500, 500)
mainloop()
I've decided that, instead of sticking a call directly to mainloop anywhere in my script, I'll just add it as part of atexit - that is, when the Python interpreter decides it's time to start closing down, it's going to enter Tk's mainloop. This then prevents it from finishing the shut down sequence until the user actually tells Tk to quit (IE, with command-Q on a Mac, or by clicking on the red X in Windows.)
from Tkinter import Tk
root = Tk()
import atexit
atexit.register(root.mainloop)
There seems to be no need to call mainloop from a system command line. The Python interpreter will continue running without it, because it's waiting for further input from you (until you run exit()).