I have much experience with Python, but I'm just now learning Tkinter and the following code isn't working:
root = Tk()
root.mainloop()
It spits out the error message
"NameError: name 'Tk' is not defined"
It seems you are simply not importing the tkinter library.
The quick solution is to add from tkinter import * to the top of your file.
However, global imports are generally a bad idea. I know lots of tkinter tutorials start out this way, but they shouldn't. I recommend doing it this way:
import tkinter as tk
root = tk.Tk()
root.mainloop()
It requires that you prefix every tkinter command with tk., but it makes your code easier to understand, and easier to maintain over time. If, for example, you decide to import ttk (some modern looking tkinter widgets), it is impossible to know if Button(...) refers to the ttk button or the tk button if you use global imports. However, tk.Button(...) and ttk.Button(...) are crystal clear.
The error occurred because the file was named as tkinter.py and caused the tkinter library import to fail.
Make sure your file name differs.
Related
Consider below example:
import tkinter as tk
root = tk.Tk()
root.title("root")
other_window = tk.Tk()
other_window.title("other_window")
root.mainloop()
and also see below example that creates instances of Tk back-to-back instead of at once, so there's exactly one instance of Tk at any given time:
import tkinter as tk
def create_window(window_to_be_closed=None):
if window_to_be_closed:
window_to_be_closed.destroy()
window = tk.Tk()
tk.Button(window, text="Quit", command=lambda arg=window : create_window(arg)).pack()
window.mainloop()
create_window()
Why is it considered bad to have multiple instances of Tk?
Is the second snippet considered a bit better, or does it suffer from
the same conditions the first code does?
Why is it considered bad to have multiple instances of Tk?
Tkinter is just a python wrapper around an embedded Tcl interpreter that imports the Tk library. When you create a root window, you create an instance of a Tcl interpreter.
Each Tcl interpreter is an isolated sandbox. An object in one sandbox cannot interact with objects in another. The most common manifestation of that is that a StringVar created in one interpreter is not visible in another. The same goes for widgets -- you can't create widgets in one interpreter that has as a parent widget in another interpreter. Images are a third case: images created in one cannot be used in another.
From a technical standpoint, there's no reason why you can't have two instances of Tk at the same time. The recommendation against it is because there's rarely an actual need to have two or more distinct Tcl interpreters, and it causes problems that are hard for beginners to grasp.
Is the second snippet considered a bit better, or does it suffer from the same conditions the first code does?
It's impossible to say whether the second example in the question is better or not without knowing what you're trying to achieve. It probably is not any better since, again, there's rarely ever a time when you actually need two instances.
The best solution 99.9% of the time is to create exactly one instance of Tk that you use for the life of your program. If you need a second or subsequent window, create instances of Toplevel. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used.
I disagree with the tkinter community discouraging the use of multiple tk.Tk windows. You can have multiple tk.Tk windows. Using multiple instances of tk.Tk is the only way to create windows that are truly independent of each other. The only mistake most people make when creating multiple tk.Tk windows is that they forget to pass in master=... when creating PhotoImages/StringVars/IntVars/...
For example look at this code:
import tkinter as tk
root = tk.Tk()
root2 = tk.Tk()
variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()
root.mainloop()
The code above doesn't work. If you add master=root2 to the tk.StringVar(), then it will work perfectly fine. This is because tkinter stores the first instance of tk.Tk() in tk._default_root. Then if you don't pass in master=..., it will assume that you wanted the window in tk._default_root.
Another thing people get wrong is how many times should .mainloop() be called. It handles events from all tk.Tk windows that are alive so you only need one .mainloop().
For folks who disagree, I'd be interested in an example of where an actual problem is caused by the multiple tk.Tk windows.
The best reference I've found so far is the Application Windows section of the tkinterbook:
In the simple examples we’ve used this far, there’s only one window on the screen; the root window. This is automatically created when you call the Tk constructor
and
If you need to create additional windows, you can use the Toplevel widget. It simply creates a new window on the screen, a window that looks and behaves pretty much like the original root window
My take on it is that a Tk instance creates a Toplevel widget, plus things like the mainloop, of which there should be only one.
Tk() initializes the hidden tcl interpreter so that the code can run, as Tkinter is just a wrapper around tcl/tk. It also automatically creates a new window. Toplevel() just creates a new window, and wont work if Tk() hasn't been instantiated, as it requires the tcl interpreter that Tk() initializes. You cannot create any Tkinter widgets without instantiating Tk(), and Toplevel is merely a widget. In the question, you use Tk() to create a second window. You should instead create another file, because initializing the tcl interpreter multiple times can get confusing, as #Bryan Oakley explains so well. Then you should do:
from os import startfile
startfile(nameOfTheOtherFile)
, because, as Toplevel() is just a widget, it closes when the Tk() window is closed. Having the other window in a separate file makes it less confusing.
I tried to implement the following code, which should be used to get the file path of a file, using tkinter's gui:
from tkinter import filedialog
from tkinter import *
root = Tk()
root.filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("jpeg files","*.jpg"),("all files","*.*")))
print (root.filename)
... the program runs, there are no errors, but also there is no tkinter window to chose a file.
I got the code from: https://pythonspot.com/tk-file-dialogs/
My operating system: Windows 10
I am using Spider from Anaconda to run the code.
EDIT:
If I change the system setting to execute in an external system terminal it works:
Why does it not work in an IPython 6.4.0 terminal?
EDIT 2:
Also changing the settings to execute in dedicated console works:
Tkinter runs in a single thread, and the .mainloop() method starts up the thread, which is actually an infinite loop till the user/another event closes the window.
This means that if you create all the widgets that should run in your window and you do not invoke .mainloop(), your code will run but the window will not come up as there is no mainloop() to begin the root Tk loop.
I am also trying to understand how to use Tkinter so could you please explain the basics?
What is the difference between the _tkinter and tkinter modules?
_tkinter is a C-based module that exposes an embedded tcl/tk interpreter. When you import it, and only it, you get access to this interpreter but you do not get access to any of the tkinter classes. This module is not designed to be imported by python scripts.
tkinter provides python-based classes that use the embedded tcl/tk interpreter. This is the module that defines Tk, Button, Text, etc.
My tkinter app will run console-free (.pyw) until I import pyttsx3. As soon as pyttsx3 is imported, the app will only run from the editor (Idle).
This is a tkinter app that runs perfectly when run from idle. I import pyttsx3, initialize it, have it speak using Windows Sapi voices, all is well, all tkinter functions operate as intended from start to finish. But outside of Idle, the app won't run in .pyw mode. It shows a black console screen for a brief moment and closes. I have checked very carefully - removing all pyttsx3 code from the app - except the import statement and, quite literally, the import statement alone is enough to cause the app to no longer run in .pyw mode.
import tkinter as tk
(runs fine in .pyw mode)
import tkinter as tk
import pyttsx3 as speak
(will not run in .pyw mode)
The question: how could simply importing a library (not even initializing or using it...just importing it) cause the tkinter app to no longer run as .pyw? Could importing a library somehow be interfering with the tkinter main loop?
Good question. If I had to guess, something in the pyttsx3 library invokes a process that is unrelated to Python, for the purpose of text-to-speech conversion. Windows probably opens a Command Prompt window in such a case since that process runs independently.
Unless the pyttsx3 library has documentation for how to suppress this—after a cursory glance, I don't see such—then I would recommend opening a new issue with the package maintainer. I believe that it would need to set the CREATE_NO_WINDOW flag when being run on Windows.
I'm in the process of making a python GUI calculator. I've been coding for no more than 3-4 week so my knowledge is limited. Anyway i want to make a pop up window that takes input from the user(Enter number, press a button to save that number in a variable).
That should be done twice(in order to add, subtract,... 2 numbers). Then i'll make another pop-up window saying: "The result is:(result)"
I know how to make an entry widget so my question is how do i make a button to save the user's input to a variable?
I highly recommend using a module called tkinter for new coders wanting to learn GUI programming in python. A complete tutorial can be found here:
http://zetcode.com/gui/tkinter/
However, creating a calculator with tkinter is pretty easy. Before you start you should think of what type of calculator you want to make, one with buttons or user input. Since you are a beginner let's do the user input method.
First if you cannot import tkinter without striking and error, head over to command prompt and write:
pip install tkinter
First things first we need to create the popup window:
from tkinter import *
window = Tk()
window.mainloop()
Now we need to create and Entry widget:
from tkinter import *
window = Tk()
User_input = Entry()
User_input.pack()
window.mainloop()
Now you will get an Entry where you will write your math problem.
Many people get confused at this stage because when they call the .get() function it doesn't work. This is because .get() makes a string. So in order to get an int you use
user_problem = int(User_input.get())
Then you use the int (numbers) the user wrote and solve them.
When using the button method assign a command callback to each button.