I'm in the middle of rewriting the code for my first tkinter application, in which I'd avoided using classes. That was a dead end and I have to finally learn class programming in python. I've encountered a very weird error and I have no idea how to fix it. I've tried, but to no effect. What I'm trying to do is specify a font for two labels in my app. It worked well in my previous, class-free code but now it gives me an error:
(...) line 56, in create_widgets
TimeFont = font.Font(family='Palatino', size=88, weight='bold')
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/font.py", line 71, in __init__
root = tkinter._default_root
AttributeError: 'module' object has no attribute '_default_root'
Here's the function I'm using for creating widgets:
def create_widgets(self):
self.set_timer = ttk.Entry(self, textvariable=self.timer)
self.start = ttk.Button(self, text='Start', command=self.start)
TimeFont = font.Font(family='Palatino', size=88, weight='bold') #the infamous line 56
self.display1 = ttk.Label(self, textvariable=self.player1, font=TimeFont)
self.display2 = ttk.Label(self, textvariable=self.player2, font=TimeFont)
And some more code "from above" in case its relevant:
from decimal import *
from tkinter import *
from tkinter import ttk
from tkinter import font
import time, _thread, subprocess
class Chclock(ttk.Frame):
#classmethod
def main(cls):
NoDefaultRoot()
root = Tk()
app = cls(root)
app.grid(sticky=NSEW)
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.resizable(True, False)
root.mainloop()
def __init__(self, root):
super().__init__(root)
root.bind('q', self.player1move)
root.bind('p', self.player2move)
root.bind('b', self.pause)
root.bind('a', self.undo)
root.bind('l', self.undo)
self.create_variables()
self.create_widgets() #here I call the function containing the error
self.grid_widgets()
self.grid_columnconfigure(0, weight=1)
It's probably something silly but I just can't understand what's causing this problem. It used to work fine...
Thanks!
Perhaps the code "NoDefaultRoot()" and the error message "object has no attribute '_default_root'" might have something to do with each other? Notice a correlation? First rule of debugging is to assume the error message is telling you something useful.
The problem is that you are creating a font object without telling that object what window it belongs to. Since you aren't telling it, it chooses to use the default root window. However, you've explicitly requested no default root window.
This is a somewhat strange way to structure your Tkinter program. I recommend reading the answers in the question Python Tkinter Program Structure
Well I've managed to find it. Since some kind person gave this question an upvote I'll post the solution: I've deleted the NoDefaultRoot() line. I'm not sure why it didn't work, and why it works now, but it does... Can someone explain what's happened in the comments? I'm really new to this stuff and the line I'd deleted came with a template.
Sorry if I made a mess.
Related
import tkinter as tk
def del_text():
textbox.delete("1.0")
window = tk.Tk()
window.configure(bg='black')
greeting = tk.Label(
text="python is a pain",
foreground="white",
background="black"
)
greeting.pack()
root = tk.tkinter()
frame = tk.Frame(root, width=300, height=300)
textbox = tk.Text(frame)
textbox.insert(window,"test")
textbox.after(10, del_text)
window.mainloop()
If I phrased it a bit weird just comment. Also yes i've copied from another guy on stack overflow, it's my first day and I'm messing around. To recreate, just copy and paste this into VScode and look at the error
Change root = tk.tkinter() to root = tk.Tk() It is unclear what you want to achieve, but do note that you are creating two windows: window and root.
Also change textbox.insert(window,"test") to textbox.insert(tk.INSERT,"test")
This should now work, creating the window window and displaying the message 'python is a pain' and creating the window root and displaying the message 'test'.
Hope I was of help!
I have some general questions regarding working code below:
tkinter is library for graphic interface as I understand I can use it interchangeably with for example Kivy?
Would it be better to learn Kivy instead or other?
Lines import tkinter as tk and from tkinter import * do exactly the same, in the first one I have alias though?
In the code below, why do I have to use ttk in ttk.Progressbar?
I imported whole library with import tkinter as tk so why do i have to reimport ttk just for progress bar? (otherwise it is not working). I would expect to work sth. like tk.Progressbar
In the line btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress), why method "fnUpdateProgress" can't have any variables? Whenever I add any, the button stop working? -> for example btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress(24)) (ofc then some changes in def of the method itself)
I created progress bar (pb) as attribute of the class Test, but wolud it be better to define it as regular variable (without self)? To be honest, code works exactly the same.
Code:
import tkinter as tk
from tkinter import *
from tkinter import ttk
from CreateProgramMain import main
import GlobalVariables
class Test():
####################################################################################
def __init__(self):
self.Progress=0
self.root = tk.Tk()
self.root.title(GlobalVariables.strAppName)
self.root.geometry('400x200')
lbl = Label(self.root, text="Please choose environment.",font=("Arial Bold", 12))
lbl.grid(column=2, row=0,sticky='e')
def btnTestClicked():
main("TEST",self)
btnTest=tk.Button(self.root, text="Test Environment", command=btnTestClicked)
btnTest.grid(column=2, row=15)
#Place progress bar
pb = ttk.Progressbar(self.root,orient='horizontal',mode='determinate',length=200)
pb.grid(column=1, row=65, columnspan=2, padx=10, pady=20)
pb["value"]=self.Progress
pb["maximum"]=100
btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress)
btnProg.grid(column=2, row=75)
self.root.mainloop()
def fnUpdateProgress(self): #why i cant insert variable inside?
pb["value"]=self.Progress
self.Progress=self.Progress+5
pb.update()
app = Test()
Thank you
it is upto you. However, tkinter and kivy both have their own syntaxes, commands, and their own usages. It might be a little difficult to convert tkinter code to kivy.
it is upto you
Yes. In the first, you have imported tkinter as tk. In the second one. You have done a wild card import. You have imported everything
Tkinter is a folder containing various modules. It contains a file called ttk.py which you have to import to access ttk.
All other classes like Label, Entry, Tk is present in __init__.py
you have to use lambda for it. If you call the function, it will be executed wlright away and the returned value is kept as the command.
Doing command=self.fnUpdateProgress(24)) will execute the function right away. Then, the returned value is kept as a command. Here, it returns None. So the command is nothing or the button is useless.
Use a lambda expression command=lambda: self.fnUpdateProgress(24))
if you don't add self it will be local to the function only. To access ot outside, it would have to be declared global, which is the point to avoid while using classes
I'd like to preface by saying I've read the docs and I guess I'm not sure how to use the provided information, or I'm just not capable of seeing the difference between the provided code and my code. I've also searched on google for relevant issues to no avail. I'm currently following this tutorial
I've made a tkinter window for a simple program I'm working on, but now I'm trying to put it in a class and everything's going downhill. The basic structure of the code in question is as follows:
from tkinter import *
class WindowManager(Tk):
def __init__(self, parent):
Tk.__init__(self, parent)
self.parent = parent
# Place items for console log
self.initialize()
def initialize(self):
self.grid()
self.text_item = Text(self, bd=0, bg="black", fg="white", height="15", width="56", )
self.text_item.grid(column=0, row=0)
def access_text(app):
app.initialize.text_item.delete('1.0', END)
def main():
app = WindowManager(None)
app.title("Main Window")
app.geometry("400x250")
app.resizable(0, 0)
app.mainloop()
access_text(app)
if __name__ == "__main__":
main()
Now this is just the basic structure of the code in question, and everything that's relevant.
An error is being thrown when the window closes saying "'function' object has no attribute 'text_item'"
My best guess is that it's trying to do something with functions in general and not accessing the code found within the function in question, but I'm not sure what the proper way to access this variable is.
Any help or clarification would be much appreciated. Thank you for your time.
My issue was I was trying to access the variable from the method when it was a local variable in the class
Instead of app.initialize.text_item I should have just had app.text_item.
Credit to #Gribouillis
For fun, I'm creating a crappy helicopter/flappybird clone using tkinter and I've run into some really bizarre behavior with regards images apparently not showing up.
(btw, using python3)
So I started with the following code just to see if I could start getting things to draw:
from tkinter import *
from PIL import ImageTk
class Bird(object):
def __init__(self, canvas, x=0, y=0):
self.canvas = canvas
photo = ImageTk.PhotoImage(file="flappy.gif")
self.bird = self.canvas.create_image(x,y,image=photo)
class Environment(Canvas):
def __init__(self, master, width=500, height=500):
super(Environment, self).__init__(master, width=width, height=height)
self.pack()
self.master = master
self.bird = Bird(self)
if __name__=="__main__":
r = Tk()
env = Environment(r)
env.pack()
r.mainloop()
Image didn't appear, all I had was a blank canvas. I thought this was odd, so I started playing around to see why that might be the case. My next step was to test that I knew how to create images, so I just made my file a basic image create:
if __name__=="__main__":
r,c=get_canv()
c.pack()
img = ImageTk.PhotoImage(file="flappy.gif")
c.create_image(100,100,image=img)
r.mainloop()
And this, predictably, works fine. So, my syntax in the prior code seemed to be correct. This is when I stumbled on something a little confusing:
if __name__=="__main__":
r,c=get_canv()
c.pack()
c.create_image(100,100,image=ImageTk.PhotoImage(file="flappy.gif"))
r.mainloop()
This didn't draw. I'm left with a blank canvas again. This is what made me suspect that maybe there was some weird threading issue going on behind the scenes. Does Anyone know why the second snippet worked and the third snippet failed?
I've seen this a number of times already. The problem is that the PhotoImage is garbage collected even though it is used in the Label! To fix the problem, just bind it to a member variable of the GUI itself:
self.photo = ImageTk.PhotoImage(file="flappy.gif")
self.bird = self.canvas.create_image(x,y,image=self.photo)
The reason it works in your second example is that the img variable exists until after the mainloop method has finished, while in your third example, it exists only during the creation of the Label.
I am trying to learn Python and trying something GUI in Python and came across this Tkinter module. My code runs but the window does not appear when I run. My code is as follows:
from Tkinter import *
#to create a root window
root = Tk()
The program runs, gives no errors but the window does not show up.
Add this to your code root.mainloop(), Here's a tutorial.
In response to your comment
#Also note that `from <module> import *` is generally frowned upon
#since it can lead to namespace collisions. It's much better to only
#explicitly import the things you need.
from Tkinter import Tk, Label
root = Tk()
w = Label(root, text="Hello, world!")
w.pack()
root.mainloop()
As other answers have pointed out, you need to call mainloop on the root object.
I recommend an OO-style of programming, and I also recommend not doing a global import (ie: not 'from Tkinter import *').
Here's a template I usually start out with:
import Tkinter as tk
class ExampleView(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
l = tk.Label(self, text="your widgets go here...", anchor="c")
l.pack(side="top", fill="both", expand=True)
if __name__=='__main__':
root = tk.Tk()
view = ExampleView(root)
view.pack(side="top", fill="both", expand=True)
root.mainloop()
This makes it easy to keep your main logic at the start of the file, and keep the creation of the root and the calling of mainloop together, which I think makes the code a little bit easier to understand. It also makes reusing this code a little easier (ie: you could create a larger program where this is one of several windows that can be created)
Add root.mainloop() at the end.